Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Merge branch 'master' of scm.gforge.inria.fr:/gitroot/simgrid/simgrid into tomerge
authorMartin Quinson <martin.quinson@loria.fr>
Fri, 24 Jul 2015 12:53:09 +0000 (14:53 +0200)
committerMartin Quinson <martin.quinson@loria.fr>
Fri, 24 Jul 2015 12:53:09 +0000 (14:53 +0200)
Conflicts:
buildtools/Cmake/DefinePackages.cmake

251 files changed:
buildtools/Cmake/DefinePackages.cmake
contrib/psg/README.txt [new file with mode: 0644]
contrib/psg/configs/bittorrent.txt [new file with mode: 0644]
contrib/psg/configs/bittorrentPSG.txt [new file with mode: 0644]
contrib/psg/configs/chord.txt [new file with mode: 0644]
contrib/psg/configs/chordPSG.txt [new file with mode: 0644]
contrib/psg/configs/edaggregation.txt [new file with mode: 0644]
contrib/psg/configs/edaggregationPSG.txt [new file with mode: 0644]
contrib/psg/configs/symphony.txt [new file with mode: 0644]
contrib/psg/configs/symphonyPSG.txt [new file with mode: 0644]
contrib/psg/lib.jar [new file with mode: 0644]
contrib/psg/platforms/psg.xml [new file with mode: 0644]
contrib/psg/run.sh [new file with mode: 0755]
contrib/psg/src/example/bittorrent/BTObserver.java [new file with mode: 0644]
contrib/psg/src/example/bittorrent/BitTorrent.java [new file with mode: 0644]
contrib/psg/src/example/bittorrent/BitfieldMsg.java [new file with mode: 0644]
contrib/psg/src/example/bittorrent/IntMsg.java [new file with mode: 0644]
contrib/psg/src/example/bittorrent/NetworkDynamics.java [new file with mode: 0644]
contrib/psg/src/example/bittorrent/NetworkInitializer.java [new file with mode: 0644]
contrib/psg/src/example/bittorrent/NodeInitializer.java [new file with mode: 0644]
contrib/psg/src/example/bittorrent/PeerSetMsg.java [new file with mode: 0644]
contrib/psg/src/example/bittorrent/SimpleEvent.java [new file with mode: 0644]
contrib/psg/src/example/bittorrent/SimpleMsg.java [new file with mode: 0644]
contrib/psg/src/example/chord/ChordInitializer.java [new file with mode: 0644]
contrib/psg/src/example/chord/ChordMessage.java [new file with mode: 0644]
contrib/psg/src/example/chord/ChordProtocol.java [new file with mode: 0644]
contrib/psg/src/example/chord/CreateNw.java [new file with mode: 0644]
contrib/psg/src/example/chord/FinalMessage.java [new file with mode: 0644]
contrib/psg/src/example/chord/LookUpMessage.java [new file with mode: 0644]
contrib/psg/src/example/chord/MessageCounterObserver.java [new file with mode: 0644]
contrib/psg/src/example/chord/NodeComparator.java [new file with mode: 0644]
contrib/psg/src/example/chord/Parameters.java [new file with mode: 0644]
contrib/psg/src/example/chord/TrafficGenerator.java [new file with mode: 0644]
contrib/psg/src/example/edaggregation/AverageED.java [new file with mode: 0644]
contrib/psg/src/example/symphony/AdapterIterableNetwork.java [new file with mode: 0644]
contrib/psg/src/example/symphony/AdapterSymphonyNodeComparator.java [new file with mode: 0644]
contrib/psg/src/example/symphony/Handler.java [new file with mode: 0644]
contrib/psg/src/example/symphony/LeaveTest.java [new file with mode: 0644]
contrib/psg/src/example/symphony/Message.java [new file with mode: 0644]
contrib/psg/src/example/symphony/NetworkSizeEstimatorProtocolInterface.java [new file with mode: 0644]
contrib/psg/src/example/symphony/RandomRouteTest.java [new file with mode: 0644]
contrib/psg/src/example/symphony/RingRouteTest.java [new file with mode: 0644]
contrib/psg/src/example/symphony/RoutingException.java [new file with mode: 0644]
contrib/psg/src/example/symphony/SimpleNetworkSizeEstimatorProtocol.java [new file with mode: 0644]
contrib/psg/src/example/symphony/SymphonyEstimationProtocol.java [new file with mode: 0644]
contrib/psg/src/example/symphony/SymphonyNetworkBuilder.java [new file with mode: 0644]
contrib/psg/src/example/symphony/SymphonyNetworkChecker.java [new file with mode: 0644]
contrib/psg/src/example/symphony/SymphonyNetworkManager.java [new file with mode: 0644]
contrib/psg/src/example/symphony/SymphonyNodeComparator.java [new file with mode: 0644]
contrib/psg/src/example/symphony/SymphonyNodeInizializer.java [new file with mode: 0644]
contrib/psg/src/example/symphony/SymphonyProtocol.java [new file with mode: 0644]
contrib/psg/src/example/symphony/SymphonyStatistics.java [new file with mode: 0644]
contrib/psg/src/example/symphony/Tuple.java [new file with mode: 0644]
contrib/psg/src/example/symphony/test/NetworkEstimationTest.java [new file with mode: 0644]
contrib/psg/src/peersim/Simulator.java [new file with mode: 0644]
contrib/psg/src/peersim/cdsim/CDProtocol.java [new file with mode: 0644]
contrib/psg/src/peersim/cdsim/CDSimulator.java [new file with mode: 0644]
contrib/psg/src/peersim/cdsim/CDState.java [new file with mode: 0644]
contrib/psg/src/peersim/cdsim/DaemonProtocol.java [new file with mode: 0644]
contrib/psg/src/peersim/cdsim/FullNextCycle.java [new file with mode: 0644]
contrib/psg/src/peersim/cdsim/NextCycle.java [new file with mode: 0644]
contrib/psg/src/peersim/cdsim/Shuffle.java [new file with mode: 0644]
contrib/psg/src/peersim/config/CheckConfig.java [new file with mode: 0644]
contrib/psg/src/peersim/config/ClassFinder.java [new file with mode: 0644]
contrib/psg/src/peersim/config/ConfigContainer.java [new file with mode: 0644]
contrib/psg/src/peersim/config/ConfigProperties.java [new file with mode: 0644]
contrib/psg/src/peersim/config/Configuration.java [new file with mode: 0644]
contrib/psg/src/peersim/config/FastConfig.java [new file with mode: 0644]
contrib/psg/src/peersim/config/IllegalParameterException.java [new file with mode: 0644]
contrib/psg/src/peersim/config/MissingParameterException.java [new file with mode: 0644]
contrib/psg/src/peersim/config/NullPrintStream.java [new file with mode: 0644]
contrib/psg/src/peersim/config/Operators.java [new file with mode: 0644]
contrib/psg/src/peersim/config/ParsedProperties.java [new file with mode: 0644]
contrib/psg/src/peersim/core/Cleanable.java [new file with mode: 0644]
contrib/psg/src/peersim/core/CommonState.java [new file with mode: 0644]
contrib/psg/src/peersim/core/Control.java [new file with mode: 0644]
contrib/psg/src/peersim/core/Fallible.java [new file with mode: 0644]
contrib/psg/src/peersim/core/GeneralNode.java [new file with mode: 0644]
contrib/psg/src/peersim/core/IdleProtocol.java [new file with mode: 0644]
contrib/psg/src/peersim/core/Linkable.java [new file with mode: 0644]
contrib/psg/src/peersim/core/MaliciousProtocol.java [new file with mode: 0644]
contrib/psg/src/peersim/core/ModifiableNode.java [new file with mode: 0644]
contrib/psg/src/peersim/core/Network.java [new file with mode: 0644]
contrib/psg/src/peersim/core/Node.java [new file with mode: 0644]
contrib/psg/src/peersim/core/OracleIdleProtocol.java [new file with mode: 0644]
contrib/psg/src/peersim/core/OverlayGraph.java [new file with mode: 0644]
contrib/psg/src/peersim/core/Protocol.java [new file with mode: 0644]
contrib/psg/src/peersim/core/Scheduler.java [new file with mode: 0644]
contrib/psg/src/peersim/dynamics/DynamicNetwork.java [new file with mode: 0644]
contrib/psg/src/peersim/dynamics/MethodInvoker.java [new file with mode: 0644]
contrib/psg/src/peersim/dynamics/NodeInitializer.java [new file with mode: 0644]
contrib/psg/src/peersim/dynamics/OscillatingNetwork.java [new file with mode: 0644]
contrib/psg/src/peersim/dynamics/RandNI.java [new file with mode: 0644]
contrib/psg/src/peersim/dynamics/StarNI.java [new file with mode: 0644]
contrib/psg/src/peersim/dynamics/WireByMethod.java [new file with mode: 0644]
contrib/psg/src/peersim/dynamics/WireFromFile.java [new file with mode: 0644]
contrib/psg/src/peersim/dynamics/WireGraph.java [new file with mode: 0644]
contrib/psg/src/peersim/dynamics/WireKOut.java [new file with mode: 0644]
contrib/psg/src/peersim/dynamics/WireRegRootedTree.java [new file with mode: 0644]
contrib/psg/src/peersim/dynamics/WireRingLattice.java [new file with mode: 0644]
contrib/psg/src/peersim/dynamics/WireScaleFreeBA.java [new file with mode: 0644]
contrib/psg/src/peersim/dynamics/WireScaleFreeDM.java [new file with mode: 0644]
contrib/psg/src/peersim/dynamics/WireStar.java [new file with mode: 0644]
contrib/psg/src/peersim/dynamics/WireWS.java [new file with mode: 0644]
contrib/psg/src/peersim/edsim/CDScheduler.java [new file with mode: 0644]
contrib/psg/src/peersim/edsim/ControlEvent.java [new file with mode: 0644]
contrib/psg/src/peersim/edsim/EDProtocol.java [new file with mode: 0644]
contrib/psg/src/peersim/edsim/EDSimulator.java [new file with mode: 0644]
contrib/psg/src/peersim/edsim/Heap.java [new file with mode: 0644]
contrib/psg/src/peersim/edsim/NextCycleEvent.java [new file with mode: 0644]
contrib/psg/src/peersim/edsim/PriorityQ.java [new file with mode: 0644]
contrib/psg/src/peersim/edsim/RandNextCycle.java [new file with mode: 0644]
contrib/psg/src/peersim/edsim/RegRandNextCycle.java [new file with mode: 0644]
contrib/psg/src/peersim/edsim/edsim_jsp.xmi [new file with mode: 0644]
contrib/psg/src/peersim/edsim/edsim_kdm.xmi [new file with mode: 0644]
contrib/psg/src/peersim/graph/BitMatrixGraph.java [new file with mode: 0644]
contrib/psg/src/peersim/graph/ConstUndirGraph.java [new file with mode: 0644]
contrib/psg/src/peersim/graph/FastUndirGraph.java [new file with mode: 0644]
contrib/psg/src/peersim/graph/Graph.java [new file with mode: 0644]
contrib/psg/src/peersim/graph/GraphAlgorithms.java [new file with mode: 0644]
contrib/psg/src/peersim/graph/GraphFactory.java [new file with mode: 0644]
contrib/psg/src/peersim/graph/GraphIO.java [new file with mode: 0644]
contrib/psg/src/peersim/graph/NeighbourListGraph.java [new file with mode: 0644]
contrib/psg/src/peersim/graph/PrefixSubGraph.java [new file with mode: 0644]
contrib/psg/src/peersim/graph/SubGraphEdges.java [new file with mode: 0644]
contrib/psg/src/peersim/graph/UndirectedGraph.java [new file with mode: 0644]
contrib/psg/src/peersim/rangesim/ProcessHandler.java [new file with mode: 0644]
contrib/psg/src/peersim/rangesim/ProcessManager.java [new file with mode: 0644]
contrib/psg/src/peersim/rangesim/RangeSimulator.java [new file with mode: 0644]
contrib/psg/src/peersim/rangesim/TaggedOutputStream.java [new file with mode: 0644]
contrib/psg/src/peersim/reports/BallExpansion.java [new file with mode: 0644]
contrib/psg/src/peersim/reports/Clustering.java [new file with mode: 0644]
contrib/psg/src/peersim/reports/ConnectivityObserver.java [new file with mode: 0644]
contrib/psg/src/peersim/reports/DegreeStats.java [new file with mode: 0644]
contrib/psg/src/peersim/reports/GraphObserver.java [new file with mode: 0644]
contrib/psg/src/peersim/reports/GraphPrinter.java [new file with mode: 0644]
contrib/psg/src/peersim/reports/GraphStats.java [new file with mode: 0644]
contrib/psg/src/peersim/reports/MemoryObserver.java [new file with mode: 0644]
contrib/psg/src/peersim/reports/RandRemoval.java [new file with mode: 0644]
contrib/psg/src/peersim/transport/E2ENetwork.java [new file with mode: 0644]
contrib/psg/src/peersim/transport/E2ETransport.java [new file with mode: 0644]
contrib/psg/src/peersim/transport/KingParser.java [new file with mode: 0644]
contrib/psg/src/peersim/transport/RouterInfo.java [new file with mode: 0644]
contrib/psg/src/peersim/transport/Transport.java [new file with mode: 0644]
contrib/psg/src/peersim/transport/TriangularMatrixParser.java [new file with mode: 0644]
contrib/psg/src/peersim/transport/UniformRandomTransport.java [new file with mode: 0644]
contrib/psg/src/peersim/transport/UniformRouterAssignment.java [new file with mode: 0644]
contrib/psg/src/peersim/transport/UnreliableTransport.java [new file with mode: 0644]
contrib/psg/src/peersim/util/ExtendedRandom.java [new file with mode: 0644]
contrib/psg/src/peersim/util/FileNameGenerator.java [new file with mode: 0644]
contrib/psg/src/peersim/util/IncrementalFreq.java [new file with mode: 0644]
contrib/psg/src/peersim/util/IncrementalStats.java [new file with mode: 0644]
contrib/psg/src/peersim/util/IndexIterator.java [new file with mode: 0644]
contrib/psg/src/peersim/util/LinearIterator.java [new file with mode: 0644]
contrib/psg/src/peersim/util/MedianStats.java [new file with mode: 0644]
contrib/psg/src/peersim/util/MomentStats.java [new file with mode: 0644]
contrib/psg/src/peersim/util/RandPermutation.java [new file with mode: 0644]
contrib/psg/src/peersim/util/StringListParser.java [new file with mode: 0644]
contrib/psg/src/peersim/util/WeightedRandPerm.java [new file with mode: 0644]
contrib/psg/src/peersim/vector/Getter.java [new file with mode: 0644]
contrib/psg/src/peersim/vector/GetterSetterFinder.java [new file with mode: 0644]
contrib/psg/src/peersim/vector/InitVectFromFile.java [new file with mode: 0644]
contrib/psg/src/peersim/vector/LinearDistribution.java [new file with mode: 0644]
contrib/psg/src/peersim/vector/Normalizer.java [new file with mode: 0644]
contrib/psg/src/peersim/vector/PeakDistribution.java [new file with mode: 0644]
contrib/psg/src/peersim/vector/Setter.java [new file with mode: 0644]
contrib/psg/src/peersim/vector/SingleValue.java [new file with mode: 0644]
contrib/psg/src/peersim/vector/SingleValueComparator.java [new file with mode: 0644]
contrib/psg/src/peersim/vector/SingleValueHolder.java [new file with mode: 0644]
contrib/psg/src/peersim/vector/SingleValueObserver.java [new file with mode: 0644]
contrib/psg/src/peersim/vector/TestVectors.java [new file with mode: 0644]
contrib/psg/src/peersim/vector/UniformDistribution.java [new file with mode: 0644]
contrib/psg/src/peersim/vector/ValueDumper.java [new file with mode: 0644]
contrib/psg/src/peersim/vector/VectAngle.java [new file with mode: 0644]
contrib/psg/src/peersim/vector/VectControl.java [new file with mode: 0644]
contrib/psg/src/peersim/vector/VectCopy.java [new file with mode: 0644]
contrib/psg/src/peersim/vector/VectorComparator.java [new file with mode: 0644]
contrib/psg/src/peersim/vector/VectorObserver.java [new file with mode: 0644]
contrib/psg/src/psgsim/NodeHost.java [new file with mode: 0644]
contrib/psg/src/psgsim/PSGDynamicNetwork.java [new file with mode: 0644]
contrib/psg/src/psgsim/PSGPlatform.java [new file with mode: 0644]
contrib/psg/src/psgsim/PSGProcessController.java [new file with mode: 0644]
contrib/psg/src/psgsim/PSGProcessCycle.java [new file with mode: 0644]
contrib/psg/src/psgsim/PSGProcessEvent.java [new file with mode: 0644]
contrib/psg/src/psgsim/PSGProcessLauncher.java [new file with mode: 0644]
contrib/psg/src/psgsim/PSGSimulator.java [new file with mode: 0644]
contrib/psg/src/psgsim/PSGTask.java [new file with mode: 0644]
contrib/psg/src/psgsim/PSGTransport.java [new file with mode: 0644]
contrib/psg/src/psgsim/Sizable.java [new file with mode: 0644]
contrib/psg/test.sh [new file with mode: 0755]
contrib/psg/tutorial.pdf [new file with mode: 0644]
doc/doxygen/introduction.doc
examples/msg/io/io.tesh
examples/msg/io/remote.tesh
examples/msg/io/storage.tesh
examples/platforms/storage/remote_io.deployment.xml [moved from examples/platforms/deployment_remote_io.xml with 100% similarity]
examples/platforms/storage/remote_io.xml [moved from examples/platforms/remote_io.xml with 100% similarity]
examples/platforms/storage/storage.xml [moved from examples/platforms/storage.xml with 64% similarity]
examples/simdag/io/io.tesh
include/simgrid/modelchecker.h
include/simgrid/platf.h
include/xbt/automaton.hpp [new file with mode: 0644]
include/xbt/mmalloc.h
include/xbt/sysdep.h
src/mc/AddressSpace.hpp
src/mc/ModelChecker.hpp
src/mc/PageStore.cpp
src/mc/PageStore.hpp
src/mc/RegionSnapshot.cpp
src/mc/RegionSnapshot.hpp
src/mc/mc_checkpoint.cpp
src/mc/mc_client_api.cpp
src/mc/mc_compare.cpp
src/mc/mc_diff.cpp
src/mc/mc_dwarf.cpp
src/mc/mc_dwarf_expression.cpp
src/mc/mc_forward.h
src/mc/mc_forward.hpp [new file with mode: 0644]
src/mc/mc_global.cpp
src/mc/mc_hash.cpp
src/mc/mc_liveness.h
src/mc/mc_location.h
src/mc/mc_member.cpp
src/mc/mc_memory_map.h
src/mc/mc_object_info.cpp
src/mc/mc_object_info.h
src/mc/mc_page_snapshot.cpp
src/mc/mc_process.cpp
src/mc/mc_process.h
src/mc/mc_safety.h
src/mc/mc_server.cpp
src/mc/mc_server.h
src/mc/mc_smx.cpp
src/mc/mc_smx.h
src/mc/mc_snapshot.cpp
src/mc/mc_snapshot.h
src/mc/mc_unw.cpp
src/mc/mc_unw.h
src/mc/mc_visited.cpp
src/mc/mc_xbt.cpp
src/mc/mcer_ignore.cpp
src/mc/memory_map.cpp
src/simgrid/util.hpp [new file with mode: 0644]
src/surf/platf_generator.c
src/surf/surf_routing.cpp
src/surf/surf_routing_cluster.cpp
src/surf/surf_routing_cluster_fat_tree.cpp
src/surf/surf_routing_cluster_torus.cpp
src/surf/surfxml_parse.c
teshsuite/mc/dwarf/dwarf.cpp
teshsuite/mc/dwarf_expression/dwarf_expression.cpp

index f238940..7bd63de 100644 (file)
@@ -394,6 +394,7 @@ endif()
 set(SIMGRID_SRC
   src/simgrid/sg_config.c
   src/simgrid/host.cpp
+  src/simgrid/util.hpp
   )
 
 set(MSG_SRC
@@ -603,6 +604,7 @@ set(MC_SRC
   src/mc/AddressSpace.hpp
   src/mc/AddressSpace.cpp
   src/mc/mc_forward.h
+  src/mc/mc_forward.hpp
   src/mc/mc_process.h
   src/mc/mc_process.cpp
   src/mc/mc_unw.h
@@ -699,6 +701,7 @@ set(headers_to_install
   include/xbt/RngStream.h
   include/xbt/asserts.h
   include/xbt/automaton.h
+  include/xbt/automaton.hpp
   include/xbt/base.h
   include/xbt/config.h
   include/xbt/cunit.h
diff --git a/contrib/psg/README.txt b/contrib/psg/README.txt
new file mode 100644 (file)
index 0000000..4435990
--- /dev/null
@@ -0,0 +1,48 @@
+Mon Jan 26 16:00 CEST 2015
+This is version 1.0 of PeerSimGrid
+
+1) An overview
+2) Preliminaries
+3) Compile & Run 
+
+--------------------------------------------------------------------------------------------
+1) An overview:
+PeerSimGrid (PSG) is an interface developed in Java and allows users to simulate 
+and execute their code under PeerSim or Simgrid simulator, using PeerSim implementation policy.
+       
+This archive is composed of:
+* the src/ directory containing the simulator source and examples
+* the configs/ directory containing example of configuration files
+* psg.jar, a java archive containing all libraries  
+
+
+2) Preliminaries:
+       Before using psg simulator, you need to make some changes in your configuration file:
+               * Replace the "UniformRandomTransport" transport protocol by "psgsim.PSGTransport".
+               * Replace the "simulation.endtime" by "simulation.duration"
+               * you can define your platform on the configuration file as:
+                       platform path/to/your/file.xml 
+       
+       
+3) Compile & Run:
+       In short, the way to compile and execute your code is: 
+               Compile it:                
+               $> make compile
+               
+               Test it (optional):
+               $> make test
+               This test execute two examples, (chord and edaggregation found in the example folder), under the two simulators
+               and compare their outputs.      
+               
+               Run it:
+               $> ./run.sh path/to/your/configuration_file 
+               For example: 
+                       $>./run.sh configs/chordPSG.txt 
+                       
+               For the documentation
+               $> make doc
+               
+               For the help command
+               $> make help
+               
+Note: For more informations please contact khaled.baati@gmail.com
\ No newline at end of file
diff --git a/contrib/psg/configs/bittorrent.txt b/contrib/psg/configs/bittorrent.txt
new file mode 100644 (file)
index 0000000..356b302
--- /dev/null
@@ -0,0 +1,46 @@
+#Config file for BitTorrent extension
+
+random.seed 1234567890
+simulation.endtime 1800000#6^8
+simulation.logtime 10^3
+OutputName bittorrent
+simulation.experiments 1
+
+network.size 30
+network.node peersim.core.GeneralNode
+
+protocol.urt UniformRandomTransport
+protocol.urt.mindelay 10
+protocol.urt.maxdelay 400
+
+#BE AWARE: the value "max_swarm_size" must be greater than
+#the value "peerset_size", since I have to be sure
+#that the space for the neighbor nodes is enough.
+
+protocol.bittorrent example.bittorrent.BitTorrent
+protocol.bittorrent.file_size 100
+protocol.bittorrent.max_swarm_size 80
+protocol.bittorrent.peerset_size 50
+protocol.bittorrent.duplicated_requests 1
+protocol.bittorrent.transport urt
+protocol.bittorrent.max_growth 20
+
+init.net example.bittorrent.NetworkInitializer
+init.net.protocol bittorrent
+init.net.transport urt
+init.net.newer_distr 80
+init.net.seeder_distr 15
+
+control.observer example.bittorrent.BTObserver
+control.observer.protocol bittorrent
+control.observer.step 10000
+
+control.dynamics example.bittorrent.NetworkDynamics
+control.dynamics.protocol bittorrent
+control.dynamics.newer_distr 60
+control.dynamics.minsize 20
+control.dynamics.tracker_can_die 1
+control.dynamics.step 100000
+control.dynamics.transport urt
+control.dynamics.add 0#5
+control.dynamics.remove 0#5
\ No newline at end of file
diff --git a/contrib/psg/configs/bittorrentPSG.txt b/contrib/psg/configs/bittorrentPSG.txt
new file mode 100644 (file)
index 0000000..647ccb4
--- /dev/null
@@ -0,0 +1,48 @@
+#Config file for BitTorrent extension
+OutputName bittorrent
+platform platforms/psg.xml
+unit ms
+random.seed 1234567890
+simulation.duration 1800000
+simulation.logtime 10^3
+
+simulation.experiments 1
+
+network.size 40
+network.node peersim.core.GeneralNode
+
+protocol.urt psgsim.PSGTransport
+protocol.urt.mindelay 0#10
+protocol.urt.maxdelay 0#400
+
+#BE AWARE: the value "max_swarm_size" must be greater than
+#the value "peerset_size", since I have to be sure
+#that the space for the neighbor nodes is enough.
+
+protocol.bittorrent example.bittorrent.BitTorrent
+protocol.bittorrent.file_size 100
+protocol.bittorrent.max_swarm_size 80
+protocol.bittorrent.peerset_size 50
+protocol.bittorrent.duplicated_requests 1
+protocol.bittorrent.transport urt
+protocol.bittorrent.max_growth 20
+
+init.net example.bittorrent.NetworkInitializer
+init.net.protocol bittorrent
+init.net.transport urt
+init.net.newer_distr 80
+init.net.seeder_distr 15
+
+control.observer example.bittorrent.BTObserver
+control.observer.protocol bittorrent
+control.observer.step 10000
+
+control.dynamics example.bittorrent.NetworkDynamics
+control.dynamics.protocol bittorrent
+control.dynamics.newer_distr 60
+control.dynamics.minsize 20
+control.dynamics.tracker_can_die 1
+control.dynamics.step 100000
+control.dynamics.transport urt
+control.dynamics.add 0#5
+control.dynamics.remove 0#5
\ No newline at end of file
diff --git a/contrib/psg/configs/chord.txt b/contrib/psg/configs/chord.txt
new file mode 100644 (file)
index 0000000..deeee8f
--- /dev/null
@@ -0,0 +1,51 @@
+# PEERSIM CHORD\r
+\r
+random.seed 1234567890\r
+simulation.endtime 10^4\r
+simulation.logtime 10^6\r
+OutputName chord\r
+simulation.experiments 1\r
+\r
+network.size 40\r
+protocol.tr UniformRandomTransport\r
+{\r
+       mindelay 0\r
+       maxdelay 0\r
+}\r
+\r
+protocol.chord  example.chord.ChordProtocol\r
+{\r
+       transport tr\r
+}\r
+\r
+control.traffic example.chord.TrafficGenerator\r
+{\r
+       protocol chord\r
+       step 100\r
+}\r
+\r
+init.create example.chord.CreateNw \r
+{\r
+       protocol chord\r
+       idLength 128\r
+       succListSize 12\r
+}\r
+\r
+control.observer example.chord.MessageCounterObserver\r
+{\r
+       protocol chord\r
+       step 90000\r
+}\r
+\r
+#control.dnet DynamicNetwork\r
+#{\r
+#      #add 2\r
+#      add -2\r
+#      minsize 18#3000\r
+#      maxsize 60#7000\r
+#      step 100000\r
+#      init.0 example.chord.ChordInitializer\r
+#      {      \r
+#              protocol chord\r
+#      }\r
+#}
\ No newline at end of file
diff --git a/contrib/psg/configs/chordPSG.txt b/contrib/psg/configs/chordPSG.txt
new file mode 100644 (file)
index 0000000..7e67047
--- /dev/null
@@ -0,0 +1,54 @@
+# PEERSIM CHORD\r
+\r
+random.seed 1234567890\r
+simulation.duration 10^4\r
+simulation.logtime 10^6\r
+unit sec\r
+OutputName chord\r
+platform platforms/psg.xml\r
+simulation.experiments 1\r
+\r
+network.size 40\r
+protocol.tr psgsim.PSGTransport\r
+{\r
+       mindelay 0\r
+       maxdelay 0\r
+}\r
+\r
+protocol.chord  example.chord.ChordProtocol\r
+{\r
+       transport tr\r
+}\r
+\r
+control.traffic example.chord.TrafficGenerator\r
+{\r
+       protocol chord\r
+       step 100\r
+}\r
+\r
+init.create example.chord.CreateNw \r
+{\r
+       protocol chord\r
+       idLength 128\r
+       succListSize 12\r
+}\r
+\r
+control.observer example.chord.MessageCounterObserver\r
+{\r
+       protocol chord\r
+       step 90000\r
+}\r
+\r
+\r
+#control.dnet DynamicNetwork\r
+#{\r
+#      #add 2\r
+#      add -2\r
+#      minsize 18#3000\r
+#      maxsize 60#7000\r
+#      step 100000\r
+#      init.0 example.chord.ChordInitializer\r
+#      {      \r
+#              protocol chord\r
+#      }\r
+#}\r
diff --git a/contrib/psg/configs/edaggregation.txt b/contrib/psg/configs/edaggregation.txt
new file mode 100644 (file)
index 0000000..d3aec12
--- /dev/null
@@ -0,0 +1,57 @@
+# network size
+SIZE 50
+OutputName edaggregation
+
+# parameters of periodic execution
+CYCLES 100
+CYCLE SIZE*100
+
+# parameters of message transfer
+# delay values here are relative to cycle length, in percentage,
+# eg 50 means half the cycle length, 200 twice the cycle length, etc.
+MINDELAY 0
+MAXDELAY 0
+# drop is a probability, 0<=DROP<=1
+DROP 0
+
+random.seed 1234567890
+network.size SIZE
+simulation.endtime CYCLE*CYCLES
+simulation.logtime CYCLE
+
+################### protocols ===========================
+
+protocol.link peersim.core.IdleProtocol
+
+protocol.avg example.edaggregation.AverageED
+protocol.avg.linkable link
+protocol.avg.step CYCLE
+protocol.avg.transport tr
+
+protocol.tr UnreliableTransport
+protocol.tr.transport urt
+protocol.tr.drop DROP
+
+protocol.urt UniformRandomTransport
+protocol.urt.mindelay (CYCLE*MINDELAY)/100
+protocol.urt.maxdelay (CYCLE*MAXDELAY)/100
+################### initialization ======================
+
+init.rndlink WireKOut
+init.rndlink.k 20
+init.rndlink.protocol link
+
+init.vals LinearDistribution
+init.vals.protocol avg
+init.vals.max SIZE
+init.vals.min 1
+
+init.sch CDScheduler
+init.sch.protocol avg
+init.sch.randstart
+
+################ control ==============================
+
+control.0 SingleValueObserver
+control.0.protocol avg
+control.0.step CYCLE
diff --git a/contrib/psg/configs/edaggregationPSG.txt b/contrib/psg/configs/edaggregationPSG.txt
new file mode 100644 (file)
index 0000000..8510e90
--- /dev/null
@@ -0,0 +1,57 @@
+# network size
+SIZE 50
+OutputName edaggregation
+platform platforms/psg.xml
+unit sec
+# parameters of periodic execution
+CYCLES 100
+CYCLE SIZE*100
+# parameters of message transfer
+# delay values here are relative to cycle length, in percentage,
+# eg 50 means half the cycle length, 200 twice the cycle length, etc.
+MINDELAY 0
+MAXDELAY 0
+# drop is a probability, 0<=DROP<=1
+DROP 0
+
+random.seed 1234567890
+network.size SIZE
+simulation.duration CYCLE*CYCLES
+simulation.logtime CYCLE
+
+################### protocols ===========================
+
+protocol.link peersim.core.IdleProtocol
+
+protocol.avg example.edaggregation.AverageED
+protocol.avg.linkable link
+protocol.avg.step CYCLE
+protocol.avg.transport tr
+
+protocol.tr UnreliableTransport
+protocol.tr.transport urt
+protocol.tr.drop DROP
+
+protocol.urt psgsim.PSGTransport
+protocol.urt.mindelay (CYCLE*MINDELAY)/100
+protocol.urt.maxdelay (CYCLE*MAXDELAY)/100
+################### initialization ======================
+
+init.rndlink WireKOut
+init.rndlink.k 20
+init.rndlink.protocol link
+
+init.vals LinearDistribution
+init.vals.protocol avg
+init.vals.max SIZE
+init.vals.min 1
+
+init.sch CDScheduler
+init.sch.protocol avg
+init.sch.randstart
+
+################ control ==============================
+
+control.0 SingleValueObserver
+control.0.protocol avg
+control.0.step CYCLE
diff --git a/contrib/psg/configs/symphony.txt b/contrib/psg/configs/symphony.txt
new file mode 100644 (file)
index 0000000..fb5c778
--- /dev/null
@@ -0,0 +1,154 @@
+# ::::::::::::::::::::::::::::::::::::::::::::::::::::::\r
+# :: Symphony Default Configuration\r
+# ::::::::::::::::::::::::::::::::::::::::::::::::::::::\r
+\r
+# network size\r
+SIZE 50\r
+\r
+# parameters of periodic execution\r
+CYCLES 100\r
+CYCLE SIZE/2\r
+OutputName symphony\r
+\r
+# parameters of message transfer\r
+# delay values here are relative to cycle length, in percentage,\r
+# eg 50 means half the cycle length, 200 twice the cycle length, etc.\r
+MINDELAY 0\r
+MAXDELAY 0\r
+\r
+random.seed 1234567890\r
+network.size SIZE\r
+simulation.experiments 1\r
+simulation.endtime 2000#CYCLE*CYCLES\r
+simulation.logtime CYCLE\r
+\r
+################### transports ===========================\r
+\r
+protocol.tr UniformRandomTransport \r
+{\r
+       mindelay (CYCLE*MINDELAY)/100\r
+       maxdelay (CYCLE*MAXDELAY)/100\r
+}\r
+\r
+################### protocols ===========================\r
+\r
+order.protocol link networkestimator symphony symphonynetworkmanager\r
+\r
+protocol.link peersim.core.IdleProtocol\r
+\r
+protocol.symphony example.symphony.SymphonyProtocol\r
+{\r
+       linkable link\r
+       transport tr\r
+       shortlink 4\r
+       # if commented means: longlink log(n)\r
+       #longlink 4\r
+       routing unidirectional\r
+       lookahead off\r
+}\r
+\r
+#protocol.networkestimator example.symphony.SimpleNetworkSizeEstimatorProtocol\r
+\r
+protocol.networkestimator example.symphony.SymphonyEstimationProtocol\r
+{\r
+       symphony symphony\r
+       # if commented means: s log(n)\r
+       #s 3\r
+}\r
+\r
+protocol.symphonynetworkmanager example.symphony.SymphonyNetworkManager\r
+{\r
+       symphony symphony\r
+       transport tr\r
+       networkestimator networkestimator\r
+       attempts 3\r
+       nTimeout 5\r
+       relinking on\r
+       relinkingLowerBound 0.5\r
+       relinkingUpperBound 2.0\r
+       step 4*CYCLE #useless\r
+}\r
+\r
+################### initialization ======================\r
+\r
+order.init netbuild checknet\r
+\r
+init.netbuild example.symphony.SymphonyNetworkBuilder\r
+{\r
+       symphony symphony\r
+       createLongLinks true\r
+       attempts 5\r
+}\r
+\r
+init.checknet example.symphony.SymphonyNetworkChecker\r
+{\r
+       symphony symphony\r
+       networkestimator networkestimator\r
+}\r
+\r
+################ control ==============================\r
+\r
+order.control sch checknet randomroutetest ringroutetest leavetest dnet estimationtest statistics\r
+\r
+control.randomroutetest example.symphony.RandomRouteTest\r
+{\r
+       symphony symphony\r
+       step CYCLE\r
+}\r
+\r
+control.ringroutetest example.symphony.RingRouteTest\r
+{\r
+       symphony symphony\r
+       startnode 0\r
+       step CYCLE\r
+}\r
+\r
+control.sch CDScheduler\r
+{\r
+       protocol symphonynetworkmanager\r
+       step CYCLE*2\r
+       randstart\r
+}\r
+\r
+control.checknet example.symphony.SymphonyNetworkChecker\r
+{\r
+       symphony symphony\r
+       networkestimator networkestimator\r
+       step CYCLE\r
+}\r
+\r
+control.dnet peersim.dynamics.DynamicNetwork\r
+{\r
+       add 0\r
+       maxsize 50\r
+       minsize SIZE/2\r
+       step CYCLE*2\r
+       init.0 example.symphony.SymphonyNodeInizializer\r
+       {\r
+               symphonynetworkmanager symphonynetworkmanager\r
+               symphony symphony\r
+               bootstrapnode 0\r
+       }\r
+}\r
+\r
+control.leavetest example.symphony.LeaveTest\r
+{\r
+       symphonynetworkmanager symphonynetworkmanager\r
+       n 1\r
+       minsizeOnline SIZE-1\r
+       waitTargetSizeToStart 2*SIZE\r
+       step CYCLE*2\r
+}\r
+\r
+control.statistics example.symphony.SymphonyStatistics\r
+{\r
+       symphony symphony\r
+       step (CYCLE*CYCLES)-1\r
+}\r
+\r
+control.estimationtest example.symphony.test.NetworkEstimationTest\r
+{\r
+       symphony symphony\r
+       symphonynetworkmanager symphonynetworkmanager\r
+       step CYCLE*4\r
+}
\ No newline at end of file
diff --git a/contrib/psg/configs/symphonyPSG.txt b/contrib/psg/configs/symphonyPSG.txt
new file mode 100644 (file)
index 0000000..20b7dce
--- /dev/null
@@ -0,0 +1,155 @@
+# ::::::::::::::::::::::::::::::::::::::::::::::::::::::\r
+# :: Symphony Default Configuration\r
+# ::::::::::::::::::::::::::::::::::::::::::::::::::::::\r
+\r
+# network size\r
+SIZE 50\r
+unit sec\r
+# parameters of periodic execution\r
+CYCLES 100\r
+CYCLE SIZE/2\r
+OutputName symphony\r
+platform platforms/psg.xml\r
+\r
+# parameters of message transfer\r
+# delay values here are relative to cycle length, in percentage,\r
+# eg 50 means half the cycle length, 200 twice the cycle length, etc.\r
+MINDELAY 0\r
+MAXDELAY 0\r
+\r
+random.seed 1234567890\r
+network.size SIZE\r
+simulation.experiments 1\r
+simulation.duration 2000#CYCLE*CYCLES\r
+simulation.logtime CYCLE\r
+\r
+################### transports ===========================\r
+\r
+protocol.tr psgsim.PSGTransport \r
+{\r
+       mindelay (CYCLE*MINDELAY)/100\r
+       maxdelay (CYCLE*MAXDELAY)/100\r
+}\r
+\r
+################### protocols ===========================\r
+\r
+order.protocol link networkestimator symphony symphonynetworkmanager\r
+\r
+protocol.link peersim.core.IdleProtocol\r
+\r
+protocol.symphony example.symphony.SymphonyProtocol\r
+{\r
+       linkable link\r
+       transport tr\r
+       shortlink 4\r
+       # if commented means: longlink log(n)\r
+       #longlink 4\r
+       routing unidirectional\r
+       lookahead off\r
+}\r
+\r
+#protocol.networkestimator example.symphony.SimpleNetworkSizeEstimatorProtocol\r
+\r
+protocol.networkestimator example.symphony.SymphonyEstimationProtocol\r
+{\r
+       symphony symphony\r
+       # if commented means: s log(n)\r
+       #s 3\r
+}\r
+\r
+protocol.symphonynetworkmanager example.symphony.SymphonyNetworkManager\r
+{\r
+       symphony symphony\r
+       transport tr\r
+       networkestimator networkestimator\r
+       attempts 3\r
+       nTimeout 5\r
+       relinking on\r
+       relinkingLowerBound 0.5\r
+       relinkingUpperBound 2.0\r
+       step 4*CYCLE #useless\r
+}\r
+\r
+################### initialization ======================\r
+\r
+order.init netbuild checknet\r
+\r
+init.netbuild example.symphony.SymphonyNetworkBuilder\r
+{\r
+       symphony symphony\r
+       createLongLinks true\r
+       attempts 5\r
+}\r
+\r
+init.checknet example.symphony.SymphonyNetworkChecker\r
+{\r
+       symphony symphony\r
+       networkestimator networkestimator\r
+}\r
+\r
+################ control ==============================\r
+\r
+order.control sch checknet randomroutetest ringroutetest leavetest dnet estimationtest statistics\r
+\r
+control.randomroutetest example.symphony.RandomRouteTest\r
+{\r
+       symphony symphony\r
+       step CYCLE\r
+}\r
+\r
+control.ringroutetest example.symphony.RingRouteTest\r
+{\r
+       symphony symphony\r
+       startnode 0\r
+       step CYCLE\r
+}\r
+\r
+control.sch CDScheduler\r
+{\r
+       protocol symphonynetworkmanager\r
+       step CYCLE*2\r
+       randstart\r
+}\r
+\r
+control.checknet example.symphony.SymphonyNetworkChecker\r
+{\r
+       symphony symphony\r
+       networkestimator networkestimator\r
+       step CYCLE\r
+}\r
+\r
+control.dnet peersim.dynamics.DynamicNetwork\r
+{\r
+       add 0\r
+       maxsize 50\r
+       minsize SIZE/2\r
+       step CYCLE*2\r
+       init.0 example.symphony.SymphonyNodeInizializer\r
+       {\r
+               symphonynetworkmanager symphonynetworkmanager\r
+               symphony symphony\r
+               bootstrapnode 0\r
+       }\r
+}\r
+\r
+control.leavetest example.symphony.LeaveTest\r
+{\r
+       symphonynetworkmanager symphonynetworkmanager\r
+       n 1\r
+       minsizeOnline SIZE-1\r
+       waitTargetSizeToStart 2*SIZE\r
+       step CYCLE*2\r
+}\r
+\r
+control.statistics example.symphony.SymphonyStatistics\r
+{\r
+       symphony symphony\r
+       step (CYCLE*CYCLES)-1\r
+}\r
+\r
+control.estimationtest example.symphony.test.NetworkEstimationTest\r
+{\r
+       symphony symphony\r
+       symphonynetworkmanager symphonynetworkmanager\r
+       step CYCLE*4\r
+}\r
diff --git a/contrib/psg/lib.jar b/contrib/psg/lib.jar
new file mode 100644 (file)
index 0000000..8fd65fa
Binary files /dev/null and b/contrib/psg/lib.jar differ
diff --git a/contrib/psg/platforms/psg.xml b/contrib/psg/platforms/psg.xml
new file mode 100644 (file)
index 0000000..bdd2e19
--- /dev/null
@@ -0,0 +1,23 @@
+<?xml version='1.0'?>
+<!DOCTYPE platform SYSTEM "http://simgrid.gforge.inria.fr/simgrid.dtd">
+<!--             _________
+                |          |
+                |  router  |
+    ____________|__________|_____________ backbone
+      |   |   |              |     |   |       
+    l0|        l1| l2|           l97| l96 |   | l99
+      |   |   |   ........   |     |   |
+      |                                |
+    c-0.me                             c-99.me 
+
+-->
+<platform version="3">
+<config>
+<prop id="network/latency_factor" value="1.0"/>
+</config>
+<AS  id="AS0"  routing="Full">
+  <cluster id="my_cluster_1" prefix="" suffix=""
+               radical="0-50000"       power="1Gf"  bw="200Mbps" lat="0ms"
+        bb_bw="200Mbps" bb_lat="0ms"/>
+</AS>
+</platform>
diff --git a/contrib/psg/run.sh b/contrib/psg/run.sh
new file mode 100755 (executable)
index 0000000..ecac88c
--- /dev/null
@@ -0,0 +1,15 @@
+#!/bin/bash
+
+if [ $(uname -m) = "i686" ]; then
+       eval ulimit -s 64
+else 
+       eval ulimit -s 128
+fi
+echo '------------- Start execution..';
+java -Xmx1024m -cp lib.jar:classes peersim.Simulator $1
+echo '------------- done -------------';
+exit 0
+
+
+
+
diff --git a/contrib/psg/src/example/bittorrent/BTObserver.java b/contrib/psg/src/example/bittorrent/BTObserver.java
new file mode 100644 (file)
index 0000000..ddd38da
--- /dev/null
@@ -0,0 +1,132 @@
+/*
+ * 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.config.*;
+import peersim.core.*;
+import peersim.util.*;
+
+/**
+ * This {@link Control} provides a way to keep track of some
+ * parameters of the BitTorrent network.
+ */
+ public class BTObserver implements Control {
+        
+       /**
+        *      The protocol to operate on.
+        *      @config
+        */
+       private static final String PAR_PROT="protocol";
+       
+       /**
+        *      Protocol identifier, obtained from config property
+        */
+       private final int pid;
+       
+       /**
+        *      The basic constructor that reads the configuration file.
+        *      @param prefix the configuration prefix for this class
+        */
+       public BTObserver(String prefix) {
+               pid = Configuration.getPid(prefix + "." + PAR_PROT);
+       }
+       
+       /**
+        * Prints information about the BitTorrent network
+        * and the number of leechers and seeders.
+        * Please refer to the code comments for more details.
+        * @return always false
+        */
+       public boolean execute() {
+               IncrementalFreq nodeStatusStats = new IncrementalFreq();
+               IncrementalStats neighborStats = new IncrementalStats();
+               
+               int numberOfNodes = Network.size();
+               int numberOfCompletedPieces = 0;
+               
+               // cycles from 1, since the node 0 is the tracker
+               for (int i=1; i<numberOfNodes; ++i) {
+                       
+                       // stats on number of leechers and seeders in the network
+                       // and consequently also on number of completed files in the network
+                       nodeStatusStats.add(((BitTorrent)(Network.get(i).getProtocol(pid))).getPeerStatus());
+                       
+                       // stats on number of neighbors per peer
+                       neighborStats.add(((BitTorrent)(Network.get(i).getProtocol(pid))).getNNodes());
+               }
+               
+               // number of the pieces of the file, equal for every node, here 1 is chosen,
+               // since 1 is the first "normal" node (0 is the tracker)
+               int numberOfPieces = ((BitTorrent)(Network.get(1).getProtocol(pid))).nPieces;
+       
+               for (int i=1; i<numberOfNodes; ++i) {
+                       numberOfCompletedPieces = 0;
+                       
+                       // discovers the status of the current peer (leecher or seeder)
+                       int ps = ((BitTorrent)(Network.get(i).getProtocol(pid))).getPeerStatus();
+                       String peerStatus;
+                       if (ps==0) {
+                               peerStatus = "L"; //leecher
+                       }
+                       else {
+                               peerStatus = "S"; //seeder
+                       }
+                       
+                       
+                       if (Network.get(i)!=null) {
+                               
+                               // counts the number of completed pieces for the i-th node
+                               for (int j=0; j<numberOfPieces; j++) {
+                                       if ( ((BitTorrent)(Network.get(i).getProtocol(pid))).getFileStatus()[j] == 16) {
+                                               numberOfCompletedPieces++;
+                                       }
+                               }
+                               
+                               /*
+                                * Put here the output lines of the Observer. An example is provided with
+                                * basic information and stats.
+                                * CommonState.getTime() is used to print out time references
+                                * (useful for graph plotting).
+                                */
+                               
+                               System.out.println("OBS: node " + ((BitTorrent)(Network.get(i).getProtocol(pid))).getThisNodeID() + "(" + peerStatus + ")" + "\t pieces completed: " + numberOfCompletedPieces + "\t \t down: " + ((BitTorrent)(Network.get(i).getProtocol(pid))).nPiecesDown + "\t up: " + ((BitTorrent)(Network.get(i).getProtocol(pid))).nPiecesUp + " time: " + CommonState.getTime());
+                               //System.out.println("[OBS] t " + CommonState.getTime() + "\t pc " + numberOfCompletedPieces + "\t n " + ((BitTorrent)(Network.get(i).getProtocol(pid))).getThisNodeID());
+                               //System.out.println( CommonState.getTime() + "\t" + numberOfCompletedPieces + "\t" + ((BitTorrent)(Network.get(i).getProtocol(pid))).getThisNodeID());
+
+                       }
+                       else {
+                               //System.out.println("[OBS] t " + CommonState.getTime() + "\t pc " + "0" + "\t n " + "0");
+                       }
+               
+               }
+               
+               // prints the frequency of 0 (leechers) and 1 (seeders)
+               nodeStatusStats.printAll(System.out);
+               
+               // prints the average number of neighbors per peer
+               System.out.println("Avg number of neighbors per peer: " + neighborStats.getAverage());
+               
+               return false;
+       }
+}
\ No newline at end of file
diff --git a/contrib/psg/src/example/bittorrent/BitTorrent.java b/contrib/psg/src/example/bittorrent/BitTorrent.java
new file mode 100644 (file)
index 0000000..1604a4d
--- /dev/null
@@ -0,0 +1,1989 @@
+/*
+ * 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.*;
+import peersim.config.*;
+import peersim.edsim.*;
+import peersim.transport.*;
+
+/**
+ *     This is the class that implements the BitTorrent module for Peersim
+ */
+public class BitTorrent implements EDProtocol {
+       /**
+        *      The size in Megabytes of the file being shared.
+        *      @config
+        */
+       private static final String PAR_SIZE="file_size";
+       /**
+        *      The Transport used by the the protocol.
+        *      @config
+        */
+       private static final String PAR_TRANSPORT="transport";
+       /**
+        *      The maximum number of neighbor that a node can have. 
+        *      @config
+        */
+       private static final String PAR_SWARM="max_swarm_size";
+       /**
+        *      The maximum number of peers returned by the tracker when a new
+        *      set of peers is requested through a <tt>TRACKER</tt> message.
+        *      @config
+        */
+       private static final String PAR_PEERSET_SIZE="peerset_size";
+       /**
+        *      Defines how much the network can grow with respect to the <tt>network.size</tt> 
+        *  when {@link NetworkDynamics} is used.
+        *      @config
+        */
+       private static final String PAR_MAX_GROWTH="max_growth";
+       /**
+        *      Is the number of requests of the same block sent to different peers.
+        *      @config
+        */
+       private static final String PAR_DUP_REQ = "duplicated_requests";
+       
+       /**
+        *      KEEP_ALIVE message.
+        *      @see SimpleEvent#type "Event types"
+        */
+       private static final int KEEP_ALIVE = 1;
+       
+       /**
+        *      CHOKE message.
+        *      @see SimpleEvent#type "Event types"
+        */
+       private static final int CHOKE = 2;
+       
+       /**
+        *      UNCHOKE message.
+        *      @see SimpleEvent#type "Event types"
+        */
+       private static final int UNCHOKE = 3;
+       
+       /**
+        *      INTERESTED message.
+        *      @see SimpleEvent#type "Event types"
+        */
+       private static final int INTERESTED = 4;
+       
+       /**
+        *      NOT_INTERESTED message.
+        *      @see SimpleEvent#type "Event types"
+        */
+       private static final int NOT_INTERESTED = 5;
+       
+       /**
+        *      HAVE message.
+        *      @see SimpleEvent#type "Event types"
+        */
+       private static final int HAVE = 6;
+       
+       /**
+        *      BITFIELD message.
+        *      @see SimpleEvent#type "Event types"
+        */
+       private static final int BITFIELD = 7;
+       
+       /**
+        *      REQUEST message.
+        *      @see SimpleEvent#type "Event types"
+        */
+       private static final int REQUEST = 8;
+       
+       /**
+        *      PIECE message.
+        *      @see SimpleEvent#type "Event types"
+        */     
+       private static final int PIECE = 9;
+
+       /**
+        *      CANCEL message.
+        *      @see SimpleEvent#type "Event types"
+        */     
+       private static final int CANCEL = 10;
+       
+       /**
+        *      TRACKER message.
+        *      @see SimpleEvent#type "Event types"
+        */     
+       private static final int TRACKER = 11;
+       
+       /**
+        *      PEERSET message.
+        *      @see SimpleEvent#type "Event types"
+        */     
+       private static final int PEERSET = 12;
+       
+       /**
+        *      CHOKE_TIME event.
+        *      @see SimpleEvent#type "Event types"
+        */     
+       private static final int CHOKE_TIME = 13;
+       
+       /**
+        *      OPTUNCHK_TIME event.
+        *      @see SimpleEvent#type "Event types"
+        */     
+       private static final int OPTUNCHK_TIME = 14;
+       
+       /**
+        *      ANTISNUB_TIME event.
+        *      @see SimpleEvent#type "Event types"
+        */     
+       private static final int ANTISNUB_TIME = 15;
+       
+       /**
+        *      CHECKALIVE_TIME event.
+        *      @see SimpleEvent#type "Event types"
+        */     
+       private static final int CHECKALIVE_TIME = 16;
+       
+       /**
+        *      TRACKERALIVE_TIME event.
+        *      @see SimpleEvent#type "Event types"
+        */     
+       private static final int TRACKERALIVE_TIME = 17;
+       
+       /**
+        *      DOWNLOAD_COMPLETED event.
+        *      @see SimpleEvent#type "Event types"
+        */     
+       private static final int DOWNLOAD_COMPLETED = 18;
+
+       /**
+        *      The maxium connection speed of the local node.
+        */
+       int maxBandwidth;
+       
+       /**
+        *      Stores the neighbors ordered by ID.
+        *  @see Element
+        */
+       private example.bittorrent.Element byPeer[];
+       
+       /**
+        *      Contains the neighbors ordered by bandwidth as needed by the unchocking
+        *      algorithm.
+        */
+       private example.bittorrent.Element byBandwidth[];
+       
+       /**
+        *      The Neighbors list.
+        */
+       private Neighbor cache[];
+       
+       /**
+        *      Reference to the neighbors that unchocked the local node.
+        */
+       private boolean unchokedBy[];
+       
+       /**
+        *      Number of neighbors in the cache. When it decreases under 20, a new peerset
+        *      is requested to the tracker.
+        */
+       private int nNodes = 0;
+       
+       /**
+        *      Maximum number of nodes in the network.
+        */
+       private int nMaxNodes;
+       
+       /**
+        *      The status of the local peer. 0 means that the current peer is a leecher, 1 a seeder.
+        */ 
+       private int peerStatus;
+       
+       /**
+        *      Defines how much the network can grow with respect to the <tt>network.size</tt> 
+        *  when {@link NetworkDynamics} is used.
+        */
+       public int maxGrowth;
+       
+       /**
+        *      File status of the local node. Contains the blocks owned by the local node.
+        */
+       private int status[];
+       
+       /**
+        *      Current number of Bitfield request sent. It must be taken into account 
+        *      before sending another one.
+        */
+       private int nBitfieldSent = 0;
+       
+       /**
+        *      Current number of pieces in upload from the local peer.
+        */
+       public int nPiecesUp = 0;
+       /**
+        *      Current number of pieces in download to the local peer.
+        */
+       public int nPiecesDown = 0;
+       
+       /**
+        *      Current number of piece completed.
+        */
+       private int nPieceCompleted = 0;
+       
+       /**
+        *      Current downloading piece ID, the previous lastInterested piece.
+        */
+       int currentPiece = -1;
+       
+       /**
+        *      Used to compute the average download rates in choking algorithm. Stores the
+        *      number of <tt>CHOKE</tt> events.
+        */
+       int n_choke_time = 0;
+       
+       /**
+        *      Used to send the <tt>TRACKER</tt> message when the local node has 20 neighbors
+        *      for the first time.
+        */
+       boolean lock = false;
+       
+       /**
+        *      Number of peers interested to my pieces.
+        */
+       int numInterestedPeers = 0;
+       
+       /**
+        *      Last piece for which the local node sent an <tt>INTERESTED</tt> message.
+        */
+       int lastInterested = -1;
+       
+       /** 
+        *      The status of the current piece in download. Length 16, every time the local node
+        *      receives a PIECE message, it updates the corrisponding block's cell. The cell
+        *      contains the ID for that block of that piece. If an already owned
+        *      block is received this is discarded.
+        */
+       private int pieceStatus[];
+       
+       /**     
+        *      Length of the file. Stored as number of pieces (256KB each one).
+        */
+       int nPieces;
+       
+       /**
+        *      Contains the neighbors's status of the file. Every row represents a
+        *      node and every a cell has value O if the neighbor doesn't 
+        *      have the piece, 1 otherwise. It has {@link #swarmSize} rows and {@link #nPieces}
+        *      columns.
+        */
+       int [][]swarm;
+       
+       /**     
+        *      The summation of the swarm's rows. Calculated every time a {@link #BITFIELD} message
+        *      is received and updated every time HAVE message is received.
+        */
+       int rarestPieceSet[];
+       
+       /**
+        *      The five pending block requests.
+        */
+       int pendingRequest[];
+       
+       /**
+        *      The maximum swarm size (default is 80)
+        */
+       int swarmSize;
+       
+       /**
+        *      The size of the peerset. This is the number of "friends" nodes
+        *      sent from the tracker to each new node (default: 50)
+        */
+       int peersetSize;
+       
+       /**
+        * The ID of the current node
+        */
+       private long thisNodeID;
+       
+       /**
+     * Number of duplicated requests as specified in the configuration file.
+        *      @see BitTorrent#PAR_DUP_REQ
+        */
+       private int numberOfDuplicatedRequests;
+       
+       /**
+        *      The queue where the requests to serve are stored.
+        *      The default dimension of the queue is 20.
+        */
+       Queue requestToServe = null;
+       
+       /**
+        *      The queue where the out of sequence incoming pieces are stored
+        *      waiting for the right moment to be processed.
+     * The default dimension of the queue is 100.
+        */
+       Queue incomingPieces = null;
+       
+       /**
+        *      The Transport ID.
+        *      @see BitTorrent#PAR_TRANSPORT
+        */
+       int tid;
+       
+       /**
+        *      The reference to the tracker node. If equals to <tt>null</tt>, the local
+        *      node is the tracker.
+        */
+       private Node tracker = null;
+       
+       /**
+        *      The default constructor. Reads the configuration file and initializes the
+        *      configuration parameters.
+        *      @param prefix the component prefix declared in the configuration file
+        */
+       public BitTorrent(String prefix){ // Used for the tracker's protocol
+               tid = Configuration.getPid(prefix+"."+PAR_TRANSPORT);
+               nPieces = (int)((Configuration.getInt(prefix+"."+PAR_SIZE))*1000000/256000);
+               swarmSize = (int)Configuration.getInt(prefix+"."+PAR_SWARM);
+               peersetSize = (int)Configuration.getInt(prefix+"."+PAR_PEERSET_SIZE);
+               numberOfDuplicatedRequests = (int)Configuration.getInt(prefix+"."+PAR_DUP_REQ);
+               maxGrowth = (int)Configuration.getInt(prefix+"."+PAR_MAX_GROWTH);
+               nMaxNodes = Network.getCapacity()-1;
+       }
+       
+       /**
+        *      Gets the reference to the tracker node.
+        *      @return the reference to the tracker
+        */
+       public Node getTracker(){
+               return tracker;
+       }
+       
+       /**
+        *      Gets the number of neighbors currently stored in the cache of the local node.
+        *      @return the number of neighbors in the cache
+        */
+       public int getNNodes(){
+               return this.nNodes;
+       }
+       
+       /**
+        *      Sets the reference to the tracker node.
+        *      @param t the tracker node
+        */
+       public void setTracker(Node t){
+               tracker = t;
+       }
+       
+       /**
+        *      Sets the ID of the local node.
+        *      @param id the ID of the node
+        */
+       public void setThisNodeID(long id) {
+               this.thisNodeID = id;
+       }
+       
+       /**
+        *      Gets the ID of the local node.
+        *      @return the ID of the local node
+        */
+       public long getThisNodeID(){
+               return this.thisNodeID;
+       }
+       
+       /**
+        *      Gets the file status of the local node.
+        *      @return the file status of the local node
+        */
+       public int[] getFileStatus(){
+               return this.status;
+       }
+       
+       /**
+        *      Initializes the tracker node. This method
+        *      only performs the initialization of the tracker's cache.
+        */
+       public void initializeTracker() {
+               cache = new Neighbor[nMaxNodes+maxGrowth];
+               for(int i=0; i<nMaxNodes+maxGrowth; i++){
+                       cache[i]= new Neighbor();
+               }
+       }
+       
+       /**
+        *      <p>Checks the number of neighbors and if it is equal to 20
+        *      sends a TRACKER messages to the tracker, asking for a new
+        *      peer set.</p>
+        *
+        *      <p>This method *must* be called after every call of {@link #removeNeighbor}
+        *      in {@link #processEvent}.
+        *      </p>
+        */
+       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; j<swarmSize; j++){// send the interested message to those  
+                                                                                                       // nodes which have that piece
+                                                               lastInterested = piece;
+                                                               if(alive(cache[j].node) && swarm[j][piece]==1){                                                                 
+                                                                       ev = new IntMsg(INTERESTED, node, lastInterested,0);
+//                                                                     latency = ((Transport)node.getProtocol(tid)).getLatency(node,cache[j].node);
+//                                                                     EDSimulator.add(latency,ev,cache[j].node,pid);  
+                                                                       ((Transport) node.getProtocol(tid)).send(node, cache[j].node, ev, pid);
+                                                                       cache[j].justSent();
+                                                               }
+                                                               
+                                                               if(!alive(cache[j].node)){
+                                                                       //System.out.println("unchoke2 rm neigh "+ cache[j].node.getID() );
+                                                                       removeNeighbor(cache[j].node);
+                                                                       processNeighborListSize(node,pid);
+                                                               }
+                                                       }
+                                                       block = getBlock();
+                                               }
+                                               else{ // block value referred to a real block
+                                                       if(alive(cache[senderIndex].node) && swarm[senderIndex][decode(block,0)]==1 && addRequest(block)){ // The sender has that block
+                                                               ev = new IntMsg(REQUEST, node, block,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();
+                                                       }
+                                                       else{
+                                                               if(!alive(cache[senderIndex].node)){
+                                                                       System.out.println("unchoke3 rm neigh "+ cache[senderIndex].node.getID() );
+                                                                       removeNeighbor(cache[senderIndex].node);
+                                                                       processNeighborListSize(node,pid);
+                                                               }
+                                                               return;
+                                                       }
+                                                       block = getBlock();
+                                               }
+                                       }
+                                       unchokedBy[senderIndex] = true; // I add the sender to the list
+                               }
+                               else // It should never happen.
+                               {
+                                       System.err.println("despite it should never happen, it happened");
+                                       for(int i=0; i<swarmSize; i++)
+                                               if(cache[i].node !=null)
+                                                       System.err.println(cache[i].node.getID());
+                                       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 INTERESTED: // 4, INTERESTED message.
+                       {
+                               numInterestedPeers++;
+                               Node sender = ((IntMsg)event).getSender();
+                               //System.out.println("process, interested: sender is "+sender.getID()+", local is "+node.getID());
+                               int value = ((IntMsg)event).getInt();
+                               Element e = search(sender.getID());
+                               if(e!=null){
+                                       cache[e.peer].isAlive();
+                                       cache[e.peer].interested = value;
+                               }
+                               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 NOT_INTERESTED: // 5, NOT_INTERESTED message.
+                       {
+                               numInterestedPeers--;
+                               Node sender = ((IntMsg)event).getSender();
+                               //System.out.println("process, not_interested: sender is "+sender.getID()+", local is "+node.getID());
+                               int value = ((IntMsg)event).getInt();
+                               Element e = search(sender.getID());
+                               if(e!=null){
+                                       cache[e.peer].isAlive();
+                                       if(cache[e.peer].interested == value)
+                                               cache[e.peer].interested = -1; // not interested
+                               }
+                       }; break;
+                               
+                       case HAVE: // 6, HAVE message.
+                       {               
+                               Node sender = ((IntMsg)event).getSender();
+                               //System.out.println("process, have: sender is "+sender.getID()+", local is "+node.getID());
+                               int piece = ((IntMsg)event).getInt();
+                               Element e = search(sender.getID());
+                               if(e!=null){
+                                       cache[e.peer].isAlive();
+                                       swarm[e.peer][piece]=1;
+                                       rarestPieceSet[piece]++;
+                                       boolean isSeeder = true;
+                                       for(int i=0; i<nPieces; i++){
+                                               isSeeder = isSeeder && (swarm[e.peer][i]==1);   
+                                       }
+                                       e.isSeeder = isSeeder;
+                               }
+                               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 BITFIELD: // 7, BITFIELD message
+                       {                       
+                               Node sender = ((BitfieldMsg)event).getSender();
+                               int []fileStatus = ((BitfieldMsg)event).getArray();
+                               /*Response with NACK*/
+                               if(!((BitfieldMsg)event).isRequest && !((BitfieldMsg)event).ack){
+                                       Element e = search(sender.getID());
+                                       if(e == null) // if is a response with nack that follows a request
+                                               nBitfieldSent--;
+                                       // otherwise is a response with ack that follows a duplicate
+                                       // insertion attempt
+                                       //System.out.println("process, bitfield_resp_nack: sender is "+sender.getID()+", local is "+node.getID());
+                                       return;
+                               }
+                               /*Request with NACK*/
+                               if(((BitfieldMsg)event).isRequest && !((BitfieldMsg)event).ack){
+                                       //System.out.println("process, bitfield_req_nack: sender is "+sender.getID()+", local is "+node.getID());
+                                       if(alive(sender)){
+                                               Element e = search(sender.getID());
+                                               ev = new BitfieldMsg(BITFIELD, false, true, node, status, nPieces); //response with ack
+//                                             latency = ((Transport)node.getProtocol(tid)).getLatency(node,sender);
+//                                             EDSimulator.add(latency,ev,sender,pid);
+                                               ((Transport) node.getProtocol(tid)).send(node, sender, ev, pid);
+                                               cache[e.peer].justSent();
+                                       }
+                               }
+                               /*Response with ACK*/
+                               if(!((BitfieldMsg)event).isRequest && ((BitfieldMsg)event).ack){
+                                       nBitfieldSent--;
+                                       //System.out.println("process, bitfield_resp_ack: sender is "+sender.getID()+", local is "+node.getID());
+                                       if(alive(sender)){
+                                               if(addNeighbor(sender)){
+                                                       Element e = search(sender.getID());
+                                                       cache[e.peer].isAlive();
+                                                       swarm[e.peer] = fileStatus;
+                                                       boolean isSeeder = true;
+                                                       for(int i=0; i<nPieces; i++){
+                                                               rarestPieceSet[i]+= fileStatus[i];
+                                                               isSeeder = isSeeder && (fileStatus[i]==1);
+                                                       }
+                                                       e.isSeeder = isSeeder;
+                                                       
+                                                       if(nNodes==10 && !lock){ // I begin to request pieces
+                                                               lock = true;
+                                                               int piece = getPiece();
+                                                               if(piece == -1)
+                                                                       return;
+                                                               lastInterested = piece;
+                                                               currentPiece = lastInterested;
+                                                               ev = new IntMsg(INTERESTED, node, lastInterested,0);
+                                                               for(int i=0; i<swarmSize; i++){// send the interested message to those  
+                                                                                                               // nodes which have that piece
+                                                                       if(alive(cache[i].node) && swarm[i][piece]==1){                                                                         
+//                                                                             latency = ((Transport)node.getProtocol(tid)).getLatency(node,cache[i].node);
+//                                                                             EDSimulator.add(latency,ev,cache[i].node,pid);
+                                                                               ((Transport) node.getProtocol(tid)).send(node, cache[i].node, ev, pid);
+                                                                               cache[i].justSent();
+                                                                       }
+                                                               }
+                                                               
+                                                       }
+                                                       
+                                               }
+                                       }
+                                       else
+                                               System.out.println("Sender "+sender.getID()+" not alive");
+                               }
+                               /*Request with ACK*/
+                               if(((BitfieldMsg)event).isRequest && ((BitfieldMsg)event).ack){
+                                       //System.out.println("process, bitfield_req_ack: sender is "+sender.getID()+", local is "+node.getID());
+                                       if(alive(sender)){
+                                               if(addNeighbor(sender)){
+                                                       Element e = search(sender.getID()); 
+                                                       cache[e.peer].isAlive();
+                                                       swarm[e.peer] = fileStatus;
+                                                       boolean isSeeder = true;
+                                                       for(int i=0; i<nPieces; i++){
+                                                               rarestPieceSet[i]+= fileStatus[i]; // I update the rarestPieceSet with the pieces of the new node
+                                                               isSeeder = isSeeder && (fileStatus[i]==1); // I check if the new node is a seeder
+                                                       }
+                                                       e.isSeeder = isSeeder;
+                                                       ev = new BitfieldMsg(BITFIELD, false, true, node, status, nPieces); //response with ack
+//                                                     latency = ((Transport)node.getProtocol(tid)).getLatency(node,sender);
+//                                                     EDSimulator.add(latency,ev,sender,pid);
+                                                       ((Transport) node.getProtocol(tid)).send(node, sender, ev, pid);
+                                                       cache[e.peer].justSent();
+                                                       if(nNodes==10 && !lock){ // I begin to request pieces
+                                                               int piece = getPiece();
+                                                               if(piece == -1)
+                                                                       return;
+                                                               lastInterested = piece;
+                                                               currentPiece = lastInterested;
+                                                               ev = new IntMsg(INTERESTED, node, lastInterested,0);
+                                                               for(int i=0; i<swarmSize; i++){// send the interested message to those  
+                                                                                                               // nodes which have that piece
+                                                                       if(alive(cache[i].node) && swarm[i][piece]==1){
+//                                                                             latency = ((Transport)node.getProtocol(tid)).getLatency(node,cache[i].node);
+//                                                                             EDSimulator.add(latency,ev,cache[i].node,pid);
+                                                                               ((Transport) node.getProtocol(tid)).send(node, cache[i].node, ev, pid);
+                                                                               cache[i].justSent();
+                                                                       }
+                                                               }
+                                                               
+                                                       }
+                                               }
+                                               else {
+                                                       Element e;
+                                                       if((e = search(sender.getID()))!=null){ // The sender was already in the cache
+                                                               cache[e.peer].isAlive();
+                                                               ev = new BitfieldMsg(BITFIELD, false, true, node, status, nPieces); //response with ack
+//                                                             latency = ((Transport)node.getProtocol(tid)).getLatency(node,sender);
+//                                                             EDSimulator.add(latency,ev,sender,pid);
+                                                               ((Transport) node.getProtocol(tid)).send(node, sender, ev, pid);
+                                                               cache[e.peer].justSent();
+                                                       }
+                                                       else{ // Was not be possible add the sender (nBitfield+nNodes > swarmSize)
+                                                               ev = new BitfieldMsg(BITFIELD, false, false, node, status, nPieces); //response with nack
+//                                                             latency = ((Transport)node.getProtocol(tid)).getLatency(node,sender);
+//                                                             EDSimulator.add(latency,ev,sender,pid);
+                                                               ((Transport) node.getProtocol(tid)).send(node, sender, ev, pid);
+                                                       }
+                                               }
+                                               
+                                       }
+                                       else
+                                               System.out.println("Sender "+sender.getID()+" not alive");
+                               }
+                       };break;
+                               
+                       case REQUEST: // 8, REQUEST message.
+                       {
+                               Object evnt;
+                               Node sender = ((IntMsg)event).getSender();
+                               int value = ((IntMsg)event).getInt();
+                               Element e;
+                               BitTorrent senderP;
+                               int remoteRate;
+                               int localRate;
+                               int bandwidth;
+                               int downloadTime;
+                               
+                               e = search(sender.getID());
+                               if (e==null)
+                                       return;
+                               cache[e.peer].isAlive();
+                               
+                               requestToServe.enqueue(value, sender);
+                                                               
+                               /*I serve the enqueued requests until 10 uploding pieces or an empty queue*/
+                               while(!requestToServe.empty() && nPiecesUp <10){ 
+                                       Request req = requestToServe.dequeue();
+                                       e = search(req.sender.getID());
+                                       if(e!=null && alive(req.sender)){
+//                                             ev = new IntMsg(PIECE, node, req.id);
+                                               nPiecesUp++;
+                                               e.valueUP++;
+                                               senderP = ((BitTorrent)req.sender.getProtocol(pid));
+                                               senderP.nPiecesDown++;
+                                               remoteRate = senderP.maxBandwidth/(senderP.nPiecesUp + senderP.nPiecesDown);
+                                               localRate = maxBandwidth/(nPiecesUp + nPiecesDown);
+                                               bandwidth = Math.min(remoteRate, localRate);
+                                               downloadTime = ((16*8)/(bandwidth))*1000; // in milliseconds
+                                               
+                                               ev = new IntMsg(PIECE, node, req.id, 16*8 * 1024);
+                                               ((Transport) node.getProtocol(tid)).send(node, req.sender, ev, pid);
+                                               
+//                                             latency = ((Transport)node.getProtocol(tid)).getLatency(node,req.sender);
+//                                             EDSimulator.add(latency+downloadTime,ev,req.sender,pid);
+                                               cache[e.peer].justSent();
+                                               
+                                               /*I send to me an event to indicate that the download is completed.
+                                               This prevent that, when the receiver death occurres, my value nPiecesUp
+                                               doesn't decrease.*/
+                                               evnt = new SimpleMsg(DOWNLOAD_COMPLETED, req.sender);
+//                                             EDSimulator.add(latency+downloadTime,evnt,node,pid); 
+                                               ((Transport) node.getProtocol(tid)).send(node, node, evnt, pid);
+                                       }
+                               }
+                       }; break;
+                               
+                       case PIECE: // 9, PIECE message.
+                       {
+                               Node sender = ((IntMsg)event).getSender();
+                               /*      Set the correct value for the local uploading and remote 
+                               downloading number of pieces */
+                               nPiecesDown--;
+                               
+                               if(peerStatus == 1)// To save CPU cycles
+                                       return;
+                               //System.out.println("process, piece: sender is "+sender.getID()+", local is "+node.getID());
+                               Element e = search(sender.getID());
+                               
+                               if(e==null){ //I can't accept a piece not wait
+                                       return;
+                               }
+                               e.valueDOWN++;
+                               
+                               cache[e.peer].isAlive();
+                               
+                               int value = ((IntMsg)event).getInt();
+                               int piece = decode(value,0);
+                               int block = decode(value,1);
+                               /* If the block has not been already downloaded and it belongs to
+                                       the current downloading piece.*/
+                               if(piece == currentPiece && decode(pieceStatus[block],0)!= piece){
+                                       pieceStatus[block] = value;
+                                       status[piece]++;
+                                       removeRequest(value);                                   
+                                       requestNextBlocks(node, pid, e.peer);
+                                       
+                               }else{ // Either a future piece or an owned piece
+                                       if(piece!=currentPiece && status[piece]!=16){ // Piece not owned, will be considered later
+                                               incomingPieces.enqueue(value, sender);
+                                       }
+                                       
+                               }
+                               ev = new IntMsg(CANCEL, node, value,0);
+                               /* I send a CANCEL to all nodes to which I previously requested the block*/
+                               for(int i=0; i<swarmSize; i++){ 
+                                       if(alive(cache[i].node) && unchokedBy[i]==true && swarm[i][decode(block,0)]==1 && cache[i].node != sender){
+//                                             latency = ((Transport)node.getProtocol(tid)).getLatency(node,cache[i].node);
+//                                             EDSimulator.add(latency,ev,cache[i].node,pid);
+                                               ((Transport) node.getProtocol(tid)).send(node, cache[i].node, ev, pid);
+                                               cache[i].justSent();
+                                       }
+                               }
+                               
+                               if(status[currentPiece]==16){ // if piece completed, I change the currentPiece to the next wanted                                       
+                                       nPieceCompleted++;
+                                       ev = new IntMsg(HAVE, node, currentPiece,0);
+                                       for(int i=0; i<swarmSize; i++){ // I send the HAVE for the piece
+                                               if(alive(cache[i].node)){
+//                                                     latency = ((Transport)node.getProtocol(tid)).getLatency(node,cache[i].node);
+//                                                     EDSimulator.add(latency,ev,cache[i].node,pid);
+                                                       ((Transport) node.getProtocol(tid)).send(node, cache[i].node, ev, pid);
+                                                       cache[i].justSent();
+                                               }
+                                               if(!alive(cache[i].node)){
+                                                       //System.out.println("piece3 rm neigh "+ cache[i].node.getID() );                                                       
+                                                       removeNeighbor(cache[i].node);
+                                                       processNeighborListSize(node,pid);
+                                               }
+                                       }
+                                       ev = new IntMsg(NOT_INTERESTED, node, currentPiece,0);
+                                       for(int i=0; i<swarmSize; i++){ // I send the NOT_INTERESTED to which peer I sent an INTERESTED
+                                               if(swarm[i][piece]==1 && alive(cache[i].node)){
+//                                                     latency = ((Transport)node.getProtocol(tid)).getLatency(node,cache[i].node);
+//                                                     EDSimulator.add(latency,ev,cache[i].node,pid);
+                                                       ((Transport) node.getProtocol(tid)).send(node, cache[i].node, ev, pid);
+                                                       cache[i].justSent();
+                                               }
+                                               if(!alive(cache[i].node)){
+                                                       //System.out.println("piece4 rm neigh "+ cache[i].node.getID() );                                                       
+                                                       removeNeighbor(cache[i].node);
+                                                       processNeighborListSize(node,pid);
+                                               }
+                                       }
+                                       if(nPieceCompleted == nPieces){
+                                               System.out.println("FILE COMPLETED for peer "+node.getID());
+                                               this.peerStatus = 1;    
+                                       }
+                                       
+                                       /*      I set the currentPiece to the lastInterested. Then I extract 
+                                               the queued received blocks
+                                               */
+                                       
+                                       currentPiece = lastInterested;
+                                       int m = incomingPieces.dim;
+                                       while(m > 0){ // I process the queue
+                                               m--;
+                                               Request temp = incomingPieces.dequeue();
+                                               int p = decode(temp.id,0); // piece id
+                                               int b = decode(temp.id,1); // block id
+                                               Element s = search(temp.sender.getID());
+                                               if(s==null) // if the node that sent the block in the queue is dead
+                                                       continue;
+                                               if(p==currentPiece && decode(pieceStatus[b],0)!= p){
+                                                       pieceStatus[b] = temp.id;
+                                                       status[p]++;
+                                                       removeRequest(temp.id);
+                                                       requestNextBlocks(node, pid, s.peer);
+                                               }
+                                               else{ // The piece not currently desired will be moved to the tail
+                                                       if(p!= currentPiece) // If not a duplicate block but belongs to another piece
+                                                               incomingPieces.enqueue(temp.id,temp.sender);
+                                                       else // duplicate block
+                                                               requestNextBlocks(node, pid, s.peer);
+                                               }
+                                       }
+                               }
+                       }; break;
+                               
+                       case CANCEL:
+                       {
+                               Node sender = ((IntMsg)event).getSender();
+                               int value = ((IntMsg)event).getInt();
+                               requestToServe.remove(sender, value);
+                       };break;
+                               
+                       case PEERSET: // PEERSET message
+                       {
+                               Node sender = ((PeerSetMsg)event).getSender();
+                               //System.out.println("process, peerset: sender is "+sender.getID()+", local is "+node.getID());
+                               Neighbor n[] = ((PeerSetMsg)event).getPeerSet();
+                               
+                               for(int i=0; i<peersetSize; i++){
+                                       if( n[i]!=null && alive(n[i].node) && search(n[i].node.getID())==null && nNodes+nBitfieldSent <swarmSize-2) {
+                                               ev = new BitfieldMsg(BITFIELD, true, true, node, status, nPieces);
+//                                             latency = ((Transport)node.getProtocol(tid)).getLatency(node,n[i].node);
+//                                             EDSimulator.add(latency,ev,n[i].node,pid);
+                                               ((Transport) node.getProtocol(tid)).send(node, n[i].node, ev, pid);
+
+                                               nBitfieldSent++;
+                                               // Here I should call the Neighbor.justSent(), but here
+                                               // the node is not yet in the cache.
+                                       }
+                               }
+                       }; break;
+                               
+                       case TRACKER: // TRACKER message
+                       {
+                               
+                               int j=0;
+                               Node sender = ((SimpleMsg)event).getSender();
+                               //System.out.println("process, tracker: sender is "+sender.getID()+", local is "+node.getID());
+                               if(!alive(sender))
+                                       return;
+                               Neighbor tmp[] = new Neighbor[peersetSize];
+                               int k=0;
+                               if(nNodes <= peersetSize){
+                                       for(int i=0; i< nMaxNodes+maxGrowth; i++){
+                                               if(cache[i].node != null && cache[i].node.getID()!= sender.getID()){
+                                                       tmp[k]=cache[i];
+                                                       k++;
+                                               }
+                                       }
+                                       ev = new PeerSetMsg(PEERSET, tmp, node);
+//                                     latency = ((Transport)node.getProtocol(tid)).getLatency(node, sender);
+//                                     EDSimulator.add(latency,ev,sender,pid);
+                                       ((Transport) node.getProtocol(tid)).send(node,sender, ev, pid);
+                                       return;
+                               }
+                               
+                               while(j < peersetSize){
+                                       int i = CommonState.r.nextInt(nMaxNodes+maxGrowth);
+                                       for (int z=0; z<j; z++){
+                                               if(cache[i].node==null || tmp[z].node.getID() == cache[i].node.getID() || cache[i].node.getID() == sender.getID()){
+                                                       z=0;
+                                                       i= CommonState.r.nextInt(nMaxNodes+maxGrowth);
+                                               }
+                                       }
+                                       if(cache[i].node != null){
+                                               tmp[j] = cache[i];
+                                               j++;
+                                       }
+                               }
+                               ev = new PeerSetMsg(PEERSET, tmp, node);
+//                             latency = ((Transport)node.getProtocol(tid)).getLatency(node, sender);
+//                             EDSimulator.add(latency,ev,sender,pid);
+                               ((Transport) node.getProtocol(tid)).send(node,sender, ev, pid);
+                       }; break;
+                               
+                       case CHOKE_TIME: //Every 10 secs.
+                       {       
+                               n_choke_time++;
+                               
+                               ev = new SimpleEvent(CHOKE_TIME);
+                               EDSimulator.add(10000,ev,node,pid);
+                               int j=0;
+                               /*I copy the interested nodes in the byBandwidth array*/
+                               for(int i=0;i< swarmSize && byPeer[i].peer != -1; i++){
+                                       if(cache[byPeer[i].peer].interested > 0){
+                                               byBandwidth[j]=byPeer[i]; //shallow copy
+                                               j++;
+                                       }
+                               }
+                               
+                               /*It ensures that in the next 20sec, if there are less nodes interested
+                                       than now, those in surplus will not be ordered. */
+                               for(;j<swarmSize;j++){
+                                       byBandwidth[j]=null;
+                               }
+                               sortByBandwidth();
+                               int optimistic = 3;
+                               int luckies[] = new int[3];
+                               try{ // It takes the first three neighbors
+                                       luckies[0] = byBandwidth[0].peer;
+                                       optimistic--;
+                                       luckies[1] = byBandwidth[1].peer;
+                                       optimistic--;
+                                       luckies[2] = byBandwidth[2].peer;
+                               }
+                               catch(NullPointerException e){ // If not enough peer in byBandwidth it chooses the other romdomly 
+                                       for(int z = optimistic; z>0;z--){
+                                               int lucky = CommonState.r.nextInt(nNodes);
+                                               while(cache[byPeer[lucky].peer].status ==1 && alive(cache[byPeer[lucky].peer].node) && 
+                                                         cache[byPeer[lucky].peer].interested == 0)// until the lucky peer is already unchoked or not interested
+                                                       lucky = CommonState.r.nextInt(nNodes);
+                                               luckies[3-z]= byPeer[lucky].peer;
+                                       }
+                               }
+                               for(int i=0; i<swarmSize; i++){ // I perform the chokes and the unchokes
+                                       if((i==luckies[0] || i==luckies[1] || i==luckies[2]) &&  alive(cache[i].node) && cache[i].status != 2){ //the unchokes
+                                               cache[i].status = 1;
+                                               ev = new SimpleMsg(UNCHOKE, node);
+//                                             latency = ((Transport)node.getProtocol(tid)).getLatency(node, cache[i].node);
+//                                             EDSimulator.add(latency,ev,cache[i].node,pid);
+                                               ((Transport) node.getProtocol(tid)).send(node,cache[i].node, ev, pid);
+                                               cache[i].justSent();
+                                               //System.out.println("average time, unchoked: "+cache[i].node.getID());
+                                       }
+                                       else{ // the chokes
+                                               if(alive(cache[i].node) && (cache[i].status == 1 || cache[i].status == 2)){
+                                                       cache[i].status = 0;
+                                                       ev = new SimpleMsg(CHOKE, node);
+//                                                     latency = ((Transport)node.getProtocol(tid)).getLatency(node, cache[i].node);
+//                                                     EDSimulator.add(latency,ev,cache[i].node,pid);
+                                                       ((Transport) node.getProtocol(tid)).send(node,cache[i].node, ev, pid);
+                                                       cache[i].justSent();
+                                               }
+                                       }
+                               }
+                               
+                               if(n_choke_time%2==0){ //every 20 secs. Used in computing the average download rates
+                                       for(int i=0; i<nNodes; i++){
+                                               if(this.peerStatus == 0){ // I'm a leeacher
+                                                       byPeer[i].head20 = byPeer[i].valueDOWN;
+                                               }
+                                               else{
+                                                       byPeer[i].head20 = byPeer[i].valueUP;
+                                               }
+                                       }
+                               }
+                       }; break;
+                               
+                       case OPTUNCHK_TIME:
+                       {
+                               
+                               //System.out.println("process, optunchk_time");
+                               
+                               ev = new SimpleEvent(OPTUNCHK_TIME);
+                               EDSimulator.add(30000,ev,node,pid);
+                               int lucky = CommonState.r.nextInt(nNodes);
+                               while(cache[byPeer[lucky].peer].status ==1)// until the lucky peer is already unchoked
+                                       lucky = CommonState.r.nextInt(nNodes);
+                               if(!alive(cache[byPeer[lucky].peer].node))
+                                       return;
+                               cache[byPeer[lucky].peer].status = 1;
+                               Object msg = new SimpleMsg(UNCHOKE,node);
+//                             latency = ((Transport)node.getProtocol(tid)).getLatency(node, cache[byPeer[lucky].peer].node);
+//                             EDSimulator.add(latency,msg,cache[byPeer[lucky].peer].node,pid);
+                               ((Transport) node.getProtocol(tid)).send(node,cache[byPeer[lucky].peer].node, msg, pid);
+                               cache[byPeer[lucky].peer].justSent();
+                       }; break;
+                               
+                       case ANTISNUB_TIME:
+                       {
+                               if(this.peerStatus == 1) // I'm a seeder, I don't update the event
+                                       return;
+                               //System.out.println("process, antisnub_time");
+                               for(int i=0; i<nNodes; i++){
+                                       if(byPeer[i].valueDOWN >0 && (byPeer[i].valueDOWN - byPeer[i].head60)==0){// No blocks downloaded in 1 min
+                                               cache[byPeer[i].peer].status = 2; // I'm snubbed by it
+                                       }
+                                       byPeer[i].head60 = byPeer[i].valueDOWN;
+                               }
+                               ev = new SimpleEvent(ANTISNUB_TIME);
+                               EDSimulator.add(60000,ev,node,pid);
+                               long time = CommonState.getTime();
+                       }; break;
+                               
+                       case CHECKALIVE_TIME:
+                       {
+                               
+                               //System.out.println("process, checkalive_time");
+                               
+                               long now = CommonState.getTime();
+                               for(int i=0; i<swarmSize; i++){
+                                       /*If are at least 2 minutes (plus 1 sec of tolerance) that
+                                       I don't send anything to it.*/
+                                       if(alive(cache[i].node) && (cache[i].lastSent < (now-121000))){
+                                               Object msg = new IntMsg(KEEP_ALIVE,node,0,0);
+//                                             latency = ((Transport)node.getProtocol(tid)).getLatency(node, cache[i].node);
+//                                             EDSimulator.add(latency,msg,cache[i].node,pid);
+                                               ((Transport) node.getProtocol(tid)).send(node,cache[i].node, msg, pid);
+                                               cache[i].justSent();
+                                       }
+                                       /*If are at least 2 minutes (plus 1 sec of tolerance) that I don't
+                                       receive anything from it though I sent a keepalive 2 minutes ago*/
+                                       else{
+                                               if(cache[i].lastSeen <(now-121000) && cache[i].node != null && cache[i].lastSent < (now-121000)){
+                                                       System.out.println("process, checkalive_time, rm neigh " + cache[i].node.getID());
+                                                       if(cache[i].node.getIndex() != -1){
+                                                               System.out.println("This should never happen: I remove a node that is not effectively died");
+                                                       }
+                                                       removeNeighbor(cache[i].node);
+                                                       processNeighborListSize(node,pid);
+                                               }
+                                       }
+                               }
+                               ev = new SimpleEvent(CHECKALIVE_TIME);
+                               EDSimulator.add(120000,ev,node,pid);
+                       }; break;
+                               
+                       case TRACKERALIVE_TIME:
+                       {
+                               //System.out.println("process, trackeralive_time");
+                               if(alive(tracker)){
+                                       ev = new SimpleEvent(TRACKERALIVE_TIME);
+                                       EDSimulator.add(1800000,ev,node,pid);
+                               }
+                               else
+                                       tracker=null;
+                               
+                       }; break;
+                               
+                       case DOWNLOAD_COMPLETED:
+                       {
+                               nPiecesUp--;
+                       }; break;
+                               
+               }
+       }
+       
+       /**
+        *      Given a piece index and a block index it encodes them in an unique integer value.
+        *      @param piece the index of the piece to encode.
+        *      @param block the index of the block to encode.
+        *      @return the encoding of the piece and the block indexes.
+        */
+       private int encode(int piece, int block){
+               return (piece*100)+block;
+               
+       }
+       /** 
+        *      Returns either the piece or the block that contained in the <tt>value</tt> depending
+        *      on <tt>part</tt>: 0 means the piece value, 1 the block value.
+        *      @param value the ID of the block to decode.
+        *      @param part the information to extract from <tt>value</tt>. 0 means the piece index, 1 the block index.
+        *      @return the piece or the block index depending about the value of <tt>part</tt>
+        */
+       private int decode(int value, int part){
+               if (value==-1) // Not a true value to decode
+                       return -1;
+               if(part == 0) // I'm interested to the piece
+                       return value/100;
+               else // I'm interested to the block
+                       return value%100;
+       }
+       
+       /**
+        *      Used by {@link NodeInitializer#choosePieces(int, BitTorrent) NodeInitializer} to set 
+        *      the number of piece completed from the beginning in according with
+        *      the distribution in the configuration file.
+        *      @param number the number of piece completed
+        */
+       public void setCompleted(int number){
+               this.nPieceCompleted = number;
+       }
+       
+       /**
+        *      Sets the status (the set of blocks) of the file for the current node.
+        *  Note that a piece is considered <i>completed</i> if the number
+        *  of downloaded blocks is 16.
+        *  @param index The index of the piece
+        *  @param value Number of blocks downloaded for the piece index.
+        */
+       public void setStatus(int index, int value){
+               status[index]=value;
+       }
+       
+       /**
+        *      Sets the status of the local node.
+        *      @param status The status of the node: 1 means seeder, 0 leecher
+        */
+       public void setPeerStatus(int status){
+               this.peerStatus = status;
+       }
+       
+       /**
+        *      Gets the status of the local node.
+        *      @return The status of the local node: 1 means seeder, 0 leecher
+        */
+       public int getPeerStatus(){
+               return peerStatus;
+       }
+       
+       /**
+        *  Gets the number of blocks for a given piece owned by the local node.
+        *      @param index The index of the piece
+        *      @return Number of blocks downloaded for the piece index
+        */
+       public int getStatus(int index){
+               return status[index];   
+       }
+       
+       /**
+        *      Sets the maximum bandwdith for the local node.
+        *      @param value The value of bandwidth in Kbps
+        */
+       public void setBandwidth(int value){
+               maxBandwidth = value;
+       }
+       
+       /**
+        *      Checks if a node is still alive in the simulated network.
+        *      @param node The node to check
+        *      @return true if the node <tt>node</tt> is up, false otherwise
+        *      @see peersim.core.GeneralNode#isUp
+        */
+       public boolean alive(Node node){
+               if(node == null)
+                       return false;
+               else
+                       return node.isUp();
+       }
+               
+       /**     
+        *      Adds a neighbor to the cache of the local node.
+        *  The new neighbor is put in the first null position.
+        *      @param neighbor The neighbor node to add
+        *  @return <tt>false</tt> if the neighbor is already present in the cache (this can happen when the peer requests a
+        *      new peer set to the tracker an there is still this neighbor within) or no place is available.
+        *      Otherwise, returns true if the node is correctly added to the cache.
+        */
+       public boolean addNeighbor(Node neighbor){
+               if(search(neighbor.getID()) !=null){// if already exists
+               //      System.err.println("Node "+neighbor.getID() + " not added, already exist.");
+                       return false;
+               }
+               if(this.tracker == null){ // I'm in the tracker's BitTorrent protocol
+                       for(int i=0; i< nMaxNodes+maxGrowth; i++){
+                               if(cache[i].node == null){
+                                       cache[i].node = neighbor;
+                                       cache[i].status = 0; //chocked
+                                       cache[i].interested = -1; //not interested
+                                       this.nNodes++;
+                                       
+                                       //System.err.println("i: " + i +" nMaxNodes: " + nMaxNodes);
+                                       return true;
+                               }
+                       }
+               }
+               else{
+                       if((nNodes+nBitfieldSent) < swarmSize){
+                               //System.out.println("I'm the node " + this.thisNodeID + ", trying to add node "+neighbor.getID());
+                               for(int i=0; i<swarmSize; i++){
+                                       if(cache[i].node == null){
+                                               cache[i].node = neighbor;
+                                               cache[i].status = 0; //choked
+                                               cache[i].interested = -1; // not interested
+                                               byPeer[nNodes].peer = i;
+                                               byPeer[nNodes].ID = neighbor.getID();
+                                               sortByPeer();
+                                               this.nNodes++;
+                                               //System.out.println(neighbor.getID()+" added!");
+                                               return true;
+                                       }
+                               }
+                               System.out.println("Node not added, no places available");
+                       }
+               }
+               return false;
+       }
+       
+       /**
+        *      Removes a neighbor from the cache of the local node.
+        *      @param neighbor The node to remove
+        *      @return true if the node is correctly removed, false otherwise.
+     */
+       public boolean removeNeighbor(Node neighbor) {
+               
+               if (neighbor == null)
+                       return true;
+               
+               // this is the tracker's bittorrent protocol
+               if (this.tracker == null) {
+                       for (int i=0; i< (nMaxNodes+maxGrowth); i++) {
+                               
+                               // check the feasibility of the removal
+                               if ( (cache[i] != null) && (cache[i].node != null) &&
+                                        (cache[i].node.getID() == neighbor.getID()) ) {
+                                       cache[i].node = null;
+                                       this.nNodes--;
+                                       return true;
+                               }
+                       }
+                       return false;
+               }
+               // this is the bittorrent protocol of a peer
+               else {
+                       
+                       Element e = search(neighbor.getID());
+                       
+                       if (e != null) {
+                               for (int i=0; i<nPieces; i++) {
+                                       rarestPieceSet[i] -= swarm[e.peer][i];
+                                       swarm[e.peer][i] = 0;
+                               }
+                               
+                               cache[e.peer].node = null;
+                               cache[e.peer].status = 0;
+                               cache[e.peer].interested = -1;
+                               unchokedBy[e.peer] = false;
+                               this.nNodes--;
+                               e.peer = -1;
+                               e.ID = Integer.MAX_VALUE;
+                               e.valueUP = 0;
+                               e.valueDOWN = 0;
+                               e.head20 = 0;
+                               e.head60 = 0;
+                               sortByPeer();
+                               
+                               return true;
+                       }
+               }
+               return false;
+       }
+       
+       /**
+     * Adds a request to the pendingRequest queue.
+        *      @param block The requested block
+        *      @return true if the request has been successfully added to the queue, false otherwise
+        */
+       private boolean addRequest(int block){
+               int i=4;
+               while(i>=0 && pendingRequest[i]!=-1){
+                       i--;
+               }
+               if(i>=0){
+                       pendingRequest[i] = block;
+                       return true;
+               }
+               else { // It should never happen
+                          //System.err.println("pendingRequest queue full");
+                       return false;           
+               }
+       }
+       
+       /**
+        *      Removes the block with the given <tt>id</tt> from the {@link #pendingRequest} queue
+        *  and sorts the queue leaving the empty cell at the left.
+        *      @param id the id of the requested block
+        */
+       private void removeRequest(int id){
+               int i = 4;
+               for(; i>=0; i--){
+                       if(pendingRequest[i]==id)
+                               break;
+               }
+               for(; i>=0; i--){
+                       if(i==0)
+                               pendingRequest[i] = -1;
+                       else
+                               pendingRequest[i] = pendingRequest[i-1];
+               }
+       }
+       
+       /**
+        *      Requests new block until the {@link #pendingRequest} is full to the sender of the just received piece.
+        *      It calls {@link #getNewBlock(Node, int)} to implement the <i>strict priority</i> strategy. 
+        *      @param node the local node
+        *      @param pid the BitTorrent protocol id
+        *      @param sender the sender of the just received received piece. 
+        */
+       private void requestNextBlocks(Node node, int pid, int sender){
+               int block = getNewBlock(node, pid);
+               while(block != -2){
+                       if(unchokedBy[sender]==true && alive(cache[sender].node) && addRequest(block)){
+                               Object ev = new IntMsg(REQUEST, node, block,0);
+                               
+//                             long latency = ((Transport)node.getProtocol(tid)).getLatency(node,cache[sender].node);
+//                             EDSimulator.add(latency,ev,cache[sender].node,pid);
+                               
+                               ((Transport) node.getProtocol(tid)).send(node,cache[sender].node, ev, pid);
+                               cache[sender].justSent();
+                       }
+                       else{ // I cannot send request
+                               if(!alive(cache[sender].node) && cache[sender].node!=null){
+                                       System.out.println("piece2 rm neigh "+ cache[sender].node.getID() );
+                                       removeNeighbor(cache[sender].node);
+                                       processNeighborListSize(node,pid);
+                               }
+                               return;
+                       }
+                       block = getNewBlock(node, pid);
+               }
+       }
+       
+       /**
+        *      It returns the id of the next block to request. Sends <tt>INTERESTED</tt> if the new
+        *      block belongs to a new piece.
+        *      It uses {@link #getBlock()} to get the next block of a piece and calls {@link #getPiece()}
+        *      when all the blocks for the {@link #currentPiece} have been requested.
+        *      @param node the local node
+        *      @param pid the BitTorrent protocol id
+        *      @return -2 if no more places available in the <tt>pendingRequest</tt> queue;<br/>
+        *                      the value of the next block to request otherwise</p>
+        */
+       private int getNewBlock(Node node, int pid){
+               int block = getBlock();
+               if(block < 0){ // No more block to request for the current piece 
+                       
+                       if(block ==-2) // Pending request queue full
+                               return -2;
+                       
+                       int newPiece = getPiece();
+                       if(newPiece == -1){ // no more piece to request
+                               return -2;
+                       }
+                       
+                       lastInterested = newPiece;
+                       Object ev = new IntMsg(INTERESTED, node, lastInterested,0);
+                       
+                       for(int j=0; j<swarmSize; j++){// send the interested message to those  
+                                                                       // nodes which have that piece
+                               if(alive(cache[j].node) && swarm[j][newPiece]==1){
+//                                     long latency = ((Transport)node.getProtocol(tid)).getLatency(node,cache[j].node);
+//                                     EDSimulator.add(latency,ev,cache[j].node,pid);
+                                       ((Transport) node.getProtocol(tid)).send(node,cache[j].node, ev, pid);
+                                       cache[j].justSent();
+                               }
+                               if(!alive(cache[j].node)){
+                                       //System.out.println("piece1 rm neigh "+ cache[j].node.getID() );
+                                       
+                                       removeNeighbor(cache[j].node);
+                                       processNeighborListSize(node,pid);
+                               }
+                       }
+                       block = getBlock();
+                       return block;
+               }
+               else{
+                       // block value referred to a real block
+                       return block;
+               }
+       }
+       
+       /**
+        *      Returns the next block to request for the {@link #currentPiece}.
+        *      @return an index of a block of the <tt>currentPiece</tt> if there are still 
+        *                      available places in the {@link #pendingRequest} queue;<br/>
+        *                      -2 if the <tt>pendingRequest</tt> queue is full;<br/>
+        *                      -1 if no more blocks to request for the current piece. 
+        */
+       private int getBlock(){
+               int i=4;
+               while(i>=0 && pendingRequest[i]!=-1){ // i is the first empty position from the head
+                       i--;
+               }
+               if(i==-1){// No places in the pendingRequest available
+                                 //System.out.println("Pendig request queue full!");
+                       return -2;
+               }
+               int j;
+               //The queue is not empty & last requested block belongs to lastInterested piece 
+               if(i!=4 && decode(pendingRequest[i+1],0)==lastInterested)
+                       j=decode(pendingRequest[i+1],1)+1; // the block following the last requested
+               else // I don't know which is the next block, so I search it.
+                       j=0; 
+               /*      I search another block until the current has been already received. 
+                       *       If in pieceStatus at position j there is a block that belongs to
+                       *       lastInterested piece, means that the block j has been already
+                       *       received, otherwise I can request it.
+                       */
+               while(j<16 && decode(pieceStatus[j],0)==lastInterested){
+                       j++;
+               }
+               if(j==16) // No more block to request for lastInterested piece
+                       return -1;
+               return encode(lastInterested,j);
+       }
+       
+       /**
+        *      Returns the next correct piece to download. It choose the piece by using the
+        *      <i>random first</i> and <i>rarest first</i> policy. For the beginning 4 pieces
+        *      of a file the first one is used then the pieces are chosen using <i>rarest first</i>.
+        *      @see "Documentation about the BitTorrent module"
+        *      @return the next piece to download. If the whole file has been requested
+        *      -1 is returned.
+        */
+       private int getPiece(){
+               int piece = -1;
+               if(nPieceCompleted < 4){ //Uses random first piece
+                       piece = CommonState.r.nextInt(nPieces);
+                       while(status[piece]==16 || piece == currentPiece) // until the piece is owned
+                               piece = CommonState.r.nextInt(nPieces);
+                       return piece;
+               }
+               else{ //Uses rarest piece first
+                       int j=0;
+                       for(; j<nPieces; j++){ // I find the first not owned piece
+                               if(status[j]==0){
+                                       piece = j;
+                                       if(piece != lastInterested) // teoretically it works because
+                                                                                               // there should be only one interested 
+                                                                                               // piece not yet downloaded
+                                               break;
+                               }
+                       }
+                       if(piece==-1){ // Never entered in the previous 'if' statement; for all
+                                                  // pieces an has been sent
+                               return -1;
+                       }
+                       
+                       int rarestPieces[] = new int[nPieces-j]; // the pieces with the less number of occurences\
+                       rarestPieces[0] = j;
+                       int nValues = 1; // number of pieces less distributed in the network
+                       for(int i=j+1; i<nPieces; i++){ // Finds the rarest piece not owned
+                               if(rarestPieceSet[i]< rarestPieceSet[rarestPieces[0]] && status[i]==0){ // if strictly less than the current one
+                                       rarestPieces[0] = i; 
+                                       nValues = 1;
+                               }
+                               if(rarestPieceSet[i]==rarestPieceSet[rarestPieces[0]] && status[i]==0){ // if equal
+                                       rarestPieces[nValues] = i;
+                                       nValues++;
+                               }
+                       }
+                       
+                       piece = CommonState.r.nextInt(nValues); // one of the less owned pieces
+                       return rarestPieces[piece];
+               }
+       }
+       
+       /**
+        *      Returns the file's size as number of pieces of 256KB.
+        *      @return number of pieces that compose the file.
+        */
+       public int getNPieces(){
+               return nPieces; 
+       }
+       /**
+        *      Clone method of the class. Returns a deep copy of the BitTorrent class. Used
+        *      by the simulation to initialize the {@link peersim.core.Network}
+        *      @return the deep copy of the BitTorrent class.
+        */
+       public Object clone(){
+               Object prot = null;
+               try{
+                       prot = (BitTorrent)super.clone();
+               }
+               catch(CloneNotSupportedException e){};
+               
+               ((BitTorrent)prot).cache = new Neighbor[swarmSize];
+               for(int i=0; i<swarmSize; i++){
+                       ((BitTorrent)prot).cache[i] = new Neighbor();
+               }
+               
+               ((BitTorrent)prot).byPeer = new Element[swarmSize];
+               for(int i=0; i<swarmSize; i++){
+                       ((BitTorrent)prot).byPeer[i] = new Element();
+               }
+               
+               ((BitTorrent)prot).unchokedBy = new boolean[swarmSize];
+               
+               ((BitTorrent)prot).byBandwidth = new Element[swarmSize];
+               ((BitTorrent)prot).status = new int[nPieces];
+               ((BitTorrent)prot).pieceStatus = new int[16];
+               for(int i=0; i<16;i++)
+                       ((BitTorrent)prot).pieceStatus[i] = -1;
+               ((BitTorrent)prot).pendingRequest = new int[5];
+               for(int i=0; i<5;i++)
+                       ((BitTorrent)prot).pendingRequest[i] = -1;
+               ((BitTorrent)prot).rarestPieceSet = new int[nPieces];
+               for(int i=0; i<nPieces;i++)
+                       ((BitTorrent)prot).rarestPieceSet[i] = 0;
+               ((BitTorrent)prot).swarm = new int[swarmSize][nPieces];
+               ((BitTorrent)prot).requestToServe = new Queue(20);
+               ((BitTorrent)prot).incomingPieces = new Queue(100);
+               return prot;
+       }
+       
+       /**
+        *      Sorts {@link #byPeer} array by peer's ID. It implements the <i>InsertionSort</i>
+        *      algorithm. 
+        */
+       public void sortByPeer(){
+               int i;
+               
+               for(int j=1; j<swarmSize; j++)   // out is dividing line
+               {
+                       Element key = new Element(); 
+                       byPeer[j].copyTo(key) ;    // remove marked item
+                       i = j-1;           // start shifts at out
+                       while(i>=0 && (byPeer[i].ID > key.ID)) // until one is smaller,
+                       {
+                               byPeer[i].copyTo(byPeer[i+1]);      // shift item right,
+                               i--;            // go left one position
+                       }
+                       key.copyTo(byPeer[i+1]);         // insert marked item
+               } 
+               
+       }
+       
+       /**
+        *      Sorts the array {@link #byBandwidth} using <i>QuickSort</i> algorithm.
+        *      <tt>null</tt> elements and seeders are moved to the end of the array.
+        */
+       public void sortByBandwidth() {
+        quicksort(0, swarmSize-1);
+    }
+       
+       /**
+        *      Used by {@link #sortByBandwidth()}. It's the implementation of the
+        *      <i>QuickSort</i> algorithm.
+        *      @param left the leftmost index of the array to sort.
+        *      @param right the rightmost index of the array to sort.
+        */
+       private void quicksort(int left, int right) {
+        if (right <= left) return;
+        int i = partition(left, right);
+        quicksort(left, i-1);
+        quicksort(i+1, right);
+    }
+       
+       /**
+        *      Used by {@link #quicksort(int, int)}, partitions the subarray to sort returning
+        *      the splitting point as stated by the <i>QuickSort</i> algorithm.
+        *      @see "The <i>QuickSort</i> algorithm".
+        */
+       private int partition(int left, int right) {
+        int i = left - 1;
+        int j = right;
+        while (true) {
+            while (greater(byBandwidth[++i], byBandwidth[right]))      // find item on left to swap
+                ;                               // a[right] acts as sentinel
+            while (greater(byBandwidth[right], byBandwidth[--j])) {      // find item on right to swap
+                if (j == left) break;  // don't go out-of-bounds
+                       }
+            if (i >= j) break;                  // check if pointers cross
+            swap(i, j);                      // swap two elements into place
+        }
+        swap(i, right);                      // swap with partition element
+        return i;
+    }
+       
+       /**
+        *      Aswers to the question "is x > y?". Compares the {@link Element}s given as 
+        *      parameters. <tt>Element x</tt> is greater than <tt>y</tt> if isn't <tt>null</tt>
+        *      and in the last 20 seconds the local node has downloaded ("uploaded" if the local node is a 
+        *      seeder) more blocks than from <tt>y</tt>.
+        *      @param x the first <tt>Element</tt> to compare.
+        *      @param y the second <tt>Element</tt> to compare
+        *      @return <tt>true</tt> if x > y;<br/>
+        *                      <tt>false</tt> otherwise.
+        */
+    private boolean greater(Element x, Element y) {
+               /*
+                * Null elements and seeders are shifted at the end
+                * of the array
+                */
+               if (x==null) return false;
+               if (y==null) return true;
+               if (x.isSeeder) return false;
+               if (y.isSeeder) return true;
+               
+               // if the local node is a leecher
+               if (peerStatus==0) {
+                       if ((x.valueDOWN - x.head20) >
+                               (y.valueDOWN -y.head20))
+                               return true;
+                       else return false;
+               }
+               
+               // if peerStatus==1 (the local node is a seeder)
+               else {                  
+                       if ((x.valueUP - x.head20) >
+                               (y.valueUP -y.head20))
+                               return true;
+                       else return false;
+               }
+    }
+       
+       /**
+        *      Swaps {@link Element} <tt>i</tt> with <tt>j</tt> in the {@link #byBandwidth}.<br/>
+        *      Used by {@link #partition(int, int)}
+        *      @param i index of the first element to swap
+        *      @param j index of the second element to swap
+        */
+       private void swap(int i, int j) {
+        Element swap = byBandwidth[i];
+        byBandwidth[i] = byBandwidth[j];
+        byBandwidth[j] = swap;
+    }
+       
+       /**     Searches the node with the given ID. It does a dychotomic 
+        *      search.
+        *      @param ID ID of the node to search.
+        *      @return the {@link Element} in {@link #byPeer} which represents the node with the
+        *      given ID.
+        */
+       public Element search(long ID){
+               int low = 0;
+               int high = swarmSize-1;
+               int p = low+((high-low)/2);              //Initial probe position
+               while ( low <= high) {
+                       if ( byPeer[p] == null || byPeer[p].ID > ID)
+                               high = p - 1;
+                       else { 
+                               if( byPeer[p].ID < ID )  //Wasteful second comparison forced by syntax limitations.
+                                       low = p + 1;
+                               else
+                                       return byPeer[p];
+                       }
+                       p = low+((high-low)/2);         //Next probe position.
+               }
+               return null;    
+       }
+}
+
+/**
+ *     This class is used to store the main informations about a neighbors regarding
+ *     the calculation of the Downloading/Uploading rates. Is the class of items in 
+ *     {@link example.bittorrent.BitTorrent#byPeer} and {@link example.bittorrent.BitTorrent#byBandwidth}.
+ */
+class Element{
+       /**
+        *      ID of the represented node.
+        */
+       public long ID = Integer.MAX_VALUE;
+       /**
+        *      Index position of the node in the {@link example.bittorrent.BitTorrent#cache} array.
+        */
+       public int peer = -1; 
+       /**
+        *      Number of blocks uploaded to anyone since the beginning.
+        */
+       public int valueUP = 0;
+       /**
+        *      Number of blocks downloaded from anyone since the beginning.
+        */
+       public int valueDOWN = 0; 
+       /**
+        *      Value of either {@link #valueUP} or {@link #valueDOWN} (depending by 
+        *      {@link example.bittorrent.BitTorrent#peerStatus}) 20 seconds before.
+        */
+       public int head20 = 0;
+       /**
+        *      Value of either {@link #valueUP} or {@link #valueDOWN} (depending by 
+        *      {@link example.bittorrent.BitTorrent#peerStatus}) 60 seconds before.
+        */
+       public int head60 = 0; 
+       /**
+        *      <tt>true</tt> if the node is a seeder, <tt>false</tt> otherwise.
+        */
+       public boolean isSeeder = false;
+       /**
+        *      Makes a deep copy of the Element to <tt>destination</tt>
+        *      @param destination Element instance where to make the copy
+        */
+       public void copyTo(Element destination){
+               destination.ID = this.ID;
+               destination.peer = this.peer;
+               destination.valueUP = this.valueUP;
+               destination.valueDOWN = this.valueDOWN;
+               destination.head20 = this.head20;
+               destination.head60 = this.head60;
+       }
+}
+
+/**
+ *     This class stores information about the neighbors regarding their status. It is 
+ *     the type of the items in the {@link example.bittorrent.BitTorrent#cache}.
+ */
+class Neighbor{
+       /**
+        *      Reference to the node in the {@link peersim.core.Network}.
+        */
+       public Node node = null;
+       /**
+        *      -1 means not interested<br/>
+        *      Other values means the last piece number for which the node is interested.
+        */
+       public int interested;
+       /**
+        *      0 means CHOKED<br/>
+        *      1 means UNCHOKED<br/>
+        *      2 means SNUBBED_BY. If this value is set and the node is to be unchocked,
+        *      value 2 has the priority.
+        */
+       public int status;
+       /**
+        *      Last time a message from the node represented has been received.
+        */
+       public long lastSeen = 0; 
+       /**
+        *      Last time a message to the node represented has been sent.
+        */
+       public long lastSent = 0;
+       
+       /**
+        * Sets the last time the neighbor was seen.
+        */
+       public void isAlive(){
+               long now = CommonState.getTime();
+               this.lastSeen = now;
+       }
+       
+       /*
+        * Sets the last time the local peer sent something to the neighbor.
+        */
+       public void justSent(){
+               long now = CommonState.getTime();
+               this.lastSent = now;
+       }
+       
+}
+
+/**
+ *     Class type of the queues's items in {@link example.bittorrent.BitTorrent#incomingPieces} 
+ *     and {@link example.bittorrent.BitTorrent#requestToServe}.
+ */
+class Queue{
+       int maxSize;
+       int head = 0;
+       int tail = 0;
+       int dim = 0;
+       Request queue[];
+       
+       /**
+        *      Public constructor. Creates a queue of size <tt>size</tt>.
+        */
+       public Queue(int size){
+               maxSize = size;
+               queue = new Request[size];
+               for(int i=0; i< size; i++)
+                       queue[i]= new Request();
+       }
+       
+       /**
+        *      Enqueues the request of the block <tt>id</tt> and its <tt>sender</tt>
+        *      @param id the id of the block in the request
+        *      @param sender a reference to the sender of the request
+        *      @return <tt>true</tt> if the request has been correctly added, <tt>false</tt>
+        *      otherwise.
+        */
+       public boolean enqueue(int id, Node sender){
+               if(dim < maxSize){
+                       queue[tail%maxSize].id = id;
+                       queue[tail%maxSize].sender = sender;
+                       tail++;
+                       dim++;
+                       return true;
+               }
+               else return false;
+       }
+       
+       /**
+        *      Returns the {@link Request} in the head of the queue.
+        *      @return the element in the head.<br/>
+        *                      <tt>null</tt> if the queue is empty.
+        */
+       public Request dequeue(){
+               Request value;
+               if(dim > 0){
+                       value = queue[head%maxSize];
+                       head++;
+                       dim--;
+                       return value;
+               }
+               else return null; //empty queue
+       }
+       
+       /**
+        *      Returns the status of the queue.
+        *      @return <tt>true</tt> if the queue is empty, <tt>false</tt>
+        *      otherwise.
+        */
+       public boolean empty(){
+               return (dim == 0);
+       }
+       
+       /**
+        *      Returns <tt>true</tt> if block given as parameter is in.
+        *      @param  value the id of the block to search.
+        *      @return <tt>true</tt> if the block <tt>value</tt> is in the queue, <tt>false</tt>
+        *      otherwise.
+        */
+       public boolean contains(int value){
+               if(empty())
+                       return false;
+               for(int i=head; i<head+dim; i++){
+                       if(queue[i%maxSize].id == value)
+                               return true;
+               }
+               return false;
+       }
+       
+       /**
+        *      Removes a request from the queue.
+        *      @param sender the sender of the request.
+        *      @param value the id of the block requested.
+        *      @return <tt>true</tt> if the request has been correctly removed, <tt>false</tt>
+        *      otherwise.
+        */
+       public boolean remove(Node sender, int value){
+               if(empty())
+                       return false;
+               for(int i=head; i<head+dim; i++){
+                       if(queue[i%maxSize].id == value && queue[i%maxSize].sender == sender){
+                               for(int j=i; j>head; j--){ // Shifts the elements for the removal
+                                       queue[j%maxSize]= queue[(j-1)%maxSize];
+                               }
+                               head++;
+                               dim--;
+                               return true;
+                       }
+               }
+               return false;
+       }
+}
+
+/**
+ *     This class represent an enqueued request of a block.
+ */
+class Request{
+       /**
+        *      The id of the block.
+        */
+       public int id;
+       /**
+        *      The sender of the request.
+        */
+       public Node sender;
+}
\ No newline at end of file
diff --git a/contrib/psg/src/example/bittorrent/BitfieldMsg.java b/contrib/psg/src/example/bittorrent/BitfieldMsg.java
new file mode 100644 (file)
index 0000000..d459482
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ * 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 <tt>bitfield</tt>
+ *     message.
+ */
+public class BitfieldMsg extends SimpleMsg{
+       /**
+        *      The status of the file to transmit to neighbors nodes
+        */
+       int[] array;
+       
+       /**
+        *      Defines the type of the Bitfield message. If <tt>isRequest</tt> is true, then
+        *      the message is a request of subscription; otherwise the message is a response.
+        */
+       boolean isRequest;
+       
+       /**
+        *      <p>The ACK value used to implement <i>ack</i> and <i>nack</i> messages.</p>
+        *      <p>It has value <tt>true</tt> if the message is a reponse and the sender has inserted
+        *      the receiver in its own cache of neighbors.<br/>
+        *      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 <tt>false</tt>.<br/>
+        *      It has value <tt>false</tt> also if the message is a request and is sent when occours
+        *      an unespected message.
+        *      </p>
+        *      @see "The documentation to understand the 4 different types of Bitfield messages"
+        */
+       boolean ack;
+       
+       /**
+        *      The basic constructor of the Bitfield message.
+        *      @param type The type of the message, according to {@link SimpleMsg}
+        *      @param isRequest Defines if the message is a request or not
+        *      @param ack Defines if the message type is an <i>ack</i> or a <i>nack</i>
+        *      @param sender The sender node
+        *      @param source The array containing the status of the file
+        *      @param size The size of the array
+        */
+       public BitfieldMsg(int type, boolean isRequest, boolean ack, Node sender, int source[], int size){
+               super.type = type;
+               super.sender = sender;
+               this.isRequest = isRequest;
+               this.ack = ack;
+               this.array = new int[size];
+               for(int i=0; i<size;i++){ // it sends a copy
+                       if(source[i]==16)
+                               this.array[i] = 1;
+                       else
+                               this.array[i] = 0;
+               }
+       }
+       
+       /**
+        *      Gets the array containing the status of the file.
+        *      @return The status of the file
+        */
+       public int[] getArray(){
+               return this.array;      
+       }
+}
\ No newline at end of file
diff --git a/contrib/psg/src/example/bittorrent/IntMsg.java b/contrib/psg/src/example/bittorrent/IntMsg.java
new file mode 100644 (file)
index 0000000..a10eaea
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * 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.*;
+import psgsim.Sizable;
+
+/**
+ * This class is a {@link SimpleMsg} and acts as a container for a message that
+ * uses only an integer value.
+ */
+public class IntMsg extends SimpleMsg implements Sizable {
+
+       /**
+        * The data value (an integer) contained in the message.
+        */
+       private int integer;
+       private double size;
+
+       /**
+        * The basic constructor of the message.
+        *
+        * @param type
+        *            the type of the message
+        * @param sender
+        *            The sender node
+        * @param value
+        *            The data value of the message
+        */
+       public IntMsg(int type, Node sender, int value, double size) {
+               super.type = type;
+               super.sender = sender;
+               this.integer = value;
+               this.size = size;
+       }
+
+       /**
+        * Gets the value contained in the message.
+        *
+        * @return the integer value contained in the message
+        */
+       public int getInt() {
+               return this.integer;
+       }
+
+       @Override
+       public double getSize() {
+               // TODO Auto-generated method stub
+               return size;
+       }
+}
\ No newline at end of file
diff --git a/contrib/psg/src/example/bittorrent/NetworkDynamics.java b/contrib/psg/src/example/bittorrent/NetworkDynamics.java
new file mode 100644 (file)
index 0000000..bdbd93a
--- /dev/null
@@ -0,0 +1,289 @@
+/*
+ * 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.config.*;
+import peersim.core.*;
+import peersim.transport.*;
+import peersim.edsim.*;
+
+/**
+ * This {@link Control} can change the size of networks by adding and removing
+ * nodes. 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 NetworkDynamics implements Control {
+       private static final int TRACKER = 11;
+       private static final int CHOKE_TIME = 13;
+       private static final int OPTUNCHK_TIME = 14;
+       private static final int ANTISNUB_TIME = 15;
+       private static final int CHECKALIVE_TIME = 16;
+       private static final int TRACKERALIVE_TIME = 17;
+
+       /**
+        * The protocol to operate on.
+        *
+        * @config
+        */
+       private static final String PAR_PROT = "protocol";
+
+       /**
+        * 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";
+
+       /**
+        * Specifies if the tracker can disappear from the network. 0 means no, 1
+        * means yes
+        * 
+        * @config
+        */
+       private static final String PAR_TRACKER_DIE = "tracker_can_die";
+
+       /**
+        * The Transport used by the the control.
+        * 
+        * @config
+        */
+       private static final String PAR_TRANSPORT = "transport";
+
+       /**
+        * Specifies how many nodes will be added to the network.
+        * 
+        * @config
+        */
+       private static final String PAR_ADD = "add";
+
+       /**
+        * Specifies how many nodes will be removed from the network.
+        * 
+        * @config
+        */
+       private static final String PAR_REMOVE = "remove";
+
+       /*
+        * The following are local variables, obtained from config property.
+        */
+       private final int pid;
+       private final int tid;
+       private final int maxSize;
+       private final int minsize;
+       private boolean trackerCanDie = false; // false (value 0) by default
+       private final int add; // number of nodes to be added
+       private final int remove; // number of nodes to be removed
+
+       private final NodeInitializer init;
+       private Node tracker;
+
+       /**
+        * Standard constructor that reads the configuration parameters. Invoked by
+        * the simulation engine.
+        * 
+        * @param prefix
+        *            the configuration prefix for this class
+        */
+       public NetworkDynamics(String prefix) {
+               pid = Configuration.getPid(prefix + "." + PAR_PROT);
+               minsize = Configuration.getInt(prefix + "." + PAR_MIN, 0);
+               tid = Configuration.getPid(prefix + "." + PAR_TRANSPORT);
+               add = Configuration.getInt(prefix + "." + PAR_ADD);
+               remove = Configuration.getInt(prefix + "." + PAR_REMOVE);
+
+               /*
+                * By default, the tracker can not disappear. If
+                * control.dynamics.tracker_can_die is set to 1, the tracker can die.
+                */
+               if (Configuration.getInt(prefix + "." + PAR_TRACKER_DIE) == 1) {
+                       trackerCanDie = true;
+               }
+
+               init = new NodeInitializer("init.net");
+               tracker = Network.get(0);
+
+               maxSize = (Network.size() - 1)
+                               + ((BitTorrent) tracker.getProtocol(pid)).maxGrowth;
+       }
+
+       /**
+        * Adds n nodes to the network. New nodes can be added only if the tracker
+        * is up.
+        * 
+        * @param n
+        *            the number of nodes to add, must be non-negative.
+        */
+       protected void add(int n) {
+               if (n == 0)
+                       return;
+               // tracker is up
+               if (tracker.isUp()) {
+                       for (int i = 0; i < n; ++i) {
+                               // create a new node
+                               Node nodeToBeAdded = (Node) Network.prototype.clone();
+
+                               // add the new node to the network
+                               Network.add(nodeToBeAdded); // questo nodo sara' in posizione
+                                                                                       // Network.len -1
+
+                               /*
+                                * Initialize the new node using the NodeInitializer class; this
+                                * it the same as
+                                * init.initialize(Network.get(Network.size()-1));
+                                */
+                               init.initialize(nodeToBeAdded);
+
+                               /*
+                                * The new node sends a TRACKER message to the tracker, asking
+                                * for a list of peers. The tracker will respond with a PEERSET
+                                * message. All the related events are also attached to the new
+                                * node.
+                                */
+                               long latency =((Transport)nodeToBeAdded.getProtocol(tid)).getLatency(nodeToBeAdded,tracker);
+                               Object ev = new SimpleMsg(TRACKER, nodeToBeAdded);
+                               EDSimulator.add(latency,ev,tracker,pid);
+//                             ((Transport) nodeToBeAdded.getProtocol(tid)).send(
+//                                             nodeToBeAdded, tracker, ev, pid);
+
+                               ev = new SimpleEvent(CHOKE_TIME);
+                               EDSimulator.add(10000, ev, nodeToBeAdded, pid);
+                               ev = new SimpleEvent(OPTUNCHK_TIME);
+                               EDSimulator.add(30000, ev, nodeToBeAdded, pid);
+                               ev = new SimpleEvent(ANTISNUB_TIME);
+                               EDSimulator.add(60000, ev, nodeToBeAdded, pid);
+                               ev = new SimpleEvent(CHECKALIVE_TIME);
+                               EDSimulator.add(120000, ev, nodeToBeAdded, pid);
+                               ev = new SimpleEvent(TRACKERALIVE_TIME);
+                               EDSimulator.add(1800000, ev, nodeToBeAdded, pid);
+
+                               // add the new node to the tracker's cache
+                               if (((BitTorrent) tracker.getProtocol(pid))
+                                               .addNeighbor(nodeToBeAdded))
+                                       System.out
+                                                       .println("DYN: A new node has been added to the network.");
+                       }
+               }
+               /*
+                * Otherwise, the tracker is down and no new nodes can be added to the
+                * network.
+                */
+               else
+                       System.out.println("DYN: Tracker is down. No new nodes added.");
+       }
+
+       /**
+        * Removes n nodes from the network. A node can be removed either if the
+        * tracker is up or down; if the tracker is up, the node to be removed will
+        * be removed also from the tracker's cache.
+        *
+        * @param n
+        *            the number of nodes to remove.
+        */
+       protected void remove(int n) {
+               // the index of the node to be removed
+               int nodeIndex = 0;
+
+               for (int i = 0; i < n; ++i) {
+                       nodeIndex = CommonState.r.nextInt(Network.size());
+                       // if the tracker can not disappear from the network
+                       if (!trackerCanDie) {
+                               /*
+                                * Choose an index for the node to be removed. The value 0 will
+                                * be discarded, since the tracker cannot disappear. Non
+                                * existing nodes cannot be removed: if the returned index
+                                * corresponds to a non-existing node, a new index will be
+                                * generated.
+                                */
+                               while (nodeIndex == 0) {
+                                       nodeIndex = CommonState.r.nextInt(Network.size());
+                               }
+                       }
+                       // otherwise, also the tracker can disappear
+                       else {
+                               nodeIndex = CommonState.r.nextInt(Network.size());
+                       }
+
+                       // a warning message
+                       // if (nodeIndex==0)
+                       // System.out.println("DYN: The tracker is going to disapper.");
+
+                       // remove the node with the given index from the network
+                       Node nodeToBeRemoved = Network.remove(nodeIndex);
+
+                       // then remove it from the tracker's cache, if it is possible (= the
+                       // tracker is up);
+                       if (tracker.isUp()) {
+                               if (((BitTorrent) tracker.getProtocol(pid))
+                                               .removeNeighbor(nodeToBeRemoved))
+                                       System.err
+                                                       .println("DYN: A node has been removed from the network.");
+                       } else { // the tracker is down
+                               System.err.println("DYN: The tracker is DOWN!");
+                       }
+               }
+       }
+
+       /**
+        * Calls {@link #add(int)} or {@link #remove} with the parameters defined by
+        * the configuration.
+        * 
+        * @return always false
+        */
+       public boolean execute() {
+               int choice = (CommonState.r.nextInt(2)); // 0 or 1
+               // adding new nodes
+               if (choice == 0) {
+                       /*
+                        * If the specified number of nodes cannot be added, it tries to add
+                        * a less number of nodes without going out of bounds. Otherwise,
+                        * all specified nodes will be added.
+                        */
+                       if (Network.size() + this.add > maxSize) {
+                               System.err.println("DYN: " + (maxSize - Network.size())
+                                               + " nodes will be added.");
+                               add(maxSize - Network.size());
+                       } else {
+                               System.err
+                                               .println("DYN: " + this.add + " nodes will be added.");
+                               add(this.add);
+                       }
+               }
+               // removing existing nodes
+               else {
+                       if (Network.size() - this.remove < minsize) {
+                               System.err.println("DYN: " + (Network.size() - minsize)
+                                               + " nodes will be removed.");
+                               remove(Network.size() - minsize);
+                       } else {
+                               System.err.println("DYN: " + this.remove
+                                               + " nodes will be removed.");
+                               remove(this.remove);
+                       }
+               }
+               return false;
+       }
+}
\ No newline at end of file
diff --git a/contrib/psg/src/example/bittorrent/NetworkInitializer.java b/contrib/psg/src/example/bittorrent/NetworkInitializer.java
new file mode 100644 (file)
index 0000000..4b5ba72
--- /dev/null
@@ -0,0 +1,105 @@
+/*
+ * 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.*;
+import peersim.config.Configuration;
+import peersim.edsim.EDSimulator;
+import peersim.transport.Transport;
+import java.util.Random;
+
+/**
+ * This {@link Control} ...
+ */
+public class NetworkInitializer implements Control {
+       /**
+       * The protocol to operate on.
+       *
+       * @config
+       */
+       private static final String PAR_PROT="protocol";
+               
+       private static final String PAR_TRANSPORT="transport";
+       
+       private static final int TRACKER = 11;
+       
+       private static final int CHOKE_TIME = 13;
+       
+       private static final int OPTUNCHK_TIME = 14;
+       
+       private static final int ANTISNUB_TIME = 15;
+       
+       private static final int CHECKALIVE_TIME = 16;
+       
+       private static final int TRACKERALIVE_TIME = 17;
+       
+       /** Protocol identifier, obtained from config property */
+       private final int pid;
+       private final int tid;
+       private NodeInitializer init;
+       
+       private Random rnd;
+       
+       public NetworkInitializer(String prefix) {
+               pid = Configuration.getPid(prefix+"."+PAR_PROT);
+               tid = Configuration.getPid(prefix+"."+PAR_TRANSPORT);
+               init = new NodeInitializer(prefix);
+       }
+       
+       public boolean execute() {
+               int completed;
+               Node tracker = Network.get(0);
+               
+               // manca l'inizializzazione del tracker;
+               
+               ((BitTorrent)Network.get(0).getProtocol(pid)).initializeTracker();
+               
+               for(int i=1; i<Network.size(); i++){
+                       System.err.println("chiamate ad addNeighbor " + i);
+                       ((BitTorrent)Network.get(0).getProtocol(pid)).addNeighbor(Network.get(i));
+                       init.initialize(Network.get(i));
+               }
+               for(int i=1; i< Network.size(); i++){
+                       Node n = Network.get(i);
+                       
+                       Object ev = new SimpleMsg(TRACKER, n);
+                       long latency = ((Transport)n.getProtocol(tid)).getLatency(n,tracker);
+                       EDSimulator.add(latency,ev,tracker,pid);                        
+//                     ((Transport) n.getProtocol(tid)).send(n,tracker, ev, pid);
+
+                       ev = new SimpleEvent(CHOKE_TIME);
+                       EDSimulator.add(10000,ev,n,pid);
+                       ev = new SimpleEvent(OPTUNCHK_TIME);
+                       EDSimulator.add(30000,ev,n,pid);
+                       ev = new SimpleEvent(ANTISNUB_TIME);
+                       EDSimulator.add(60000,ev,n,pid);
+                       ev = new SimpleEvent(CHECKALIVE_TIME);
+                       EDSimulator.add(120000,ev,n,pid);
+                       ev = new SimpleEvent(TRACKERALIVE_TIME);
+                       EDSimulator.add(1800000,ev,n,pid);
+               }
+               return true;
+       }
+       
+       }
diff --git a/contrib/psg/src/example/bittorrent/NodeInitializer.java b/contrib/psg/src/example/bittorrent/NodeInitializer.java
new file mode 100644 (file)
index 0000000..df71688
--- /dev/null
@@ -0,0 +1,170 @@
+/*
+ * 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.*;
+import peersim.config.Configuration;
+
+/**
+ *     This class provides a way to initialize a single node of the network.
+ *     The initialization is performed by choosing the bandwidth of the node
+ *     and choosing how much the shared file has been downloaded.
+ */
+public class NodeInitializer{
+       
+       /**
+        *      The protocol to operate on.
+        *      @config
+        */
+       private static final String PAR_PROT="protocol";
+       
+       /**
+        *      The percentage of nodes with no downloaded pieces.
+        *      @config
+        *      @see "The documentation for an example on how to properly set this parameter."
+        */
+       private static final String PAR_NEWER_DISTR="newer_distr";
+       
+       /**
+        *      The percentage of seeders in the network.
+        *      @config
+        */
+       private static final String PAR_SEEDER_DISTR="seeder_distr";
+
+       /**
+        *      The percentage of nodes with no downloaded pieces,
+        *      as defined in {@see #PAR_NEWER_DISTR}.
+        */
+       private int newerDistr;
+       
+       /**
+        *      The percentage of seeder nodes,
+        *      as defined in {@see #PAR_SEEDER_DISTR}.
+        */
+       private int seederDistr;
+       
+       /**
+        *      The BitTorrent protocol ID.
+        */     
+       private final int pid;
+       
+       /**
+        *      The basic constructor of the class, which reads the parameters
+        *      from the configuration file.
+        *      @param prefix the configuration prefix for this class
+        */
+       public NodeInitializer(String prefix){
+               pid = Configuration.getPid(prefix+"."+PAR_PROT);
+               newerDistr = Configuration.getInt(prefix+"."+PAR_NEWER_DISTR);
+               seederDistr = Configuration.getInt(prefix+"."+PAR_SEEDER_DISTR);
+       }
+       
+       /**
+        *      Initializes the node <tt>n</tt> associating it
+        *      with the BitTorrent protocol and setting the reference to the tracker,
+        *      the status of the file and the bandwidth.
+        *      @param n The node to initialize
+        */
+       public void initialize(Node n){
+               Node tracker = Network.get(0);
+               BitTorrent p;
+               p = (BitTorrent)n.getProtocol(pid);
+               p.setTracker(tracker);
+               p.setThisNodeID(n.getID());
+               setFileStatus(p);
+               setBandwidth(p);
+       }
+
+       /**
+        *      Sets the status of the shared file according to the
+        *      probability value given by {@link #getProbability()}.
+        *      @param p The BitTorrent protocol
+        */
+       private void setFileStatus(BitTorrent p){
+               int percentage = getProbability();
+               choosePieces(percentage, p);
+       }
+       
+       /**
+        *      Set the maximum bandwidth for the node, choosing
+        *      uniformly at random among 4 values.
+        *      <p>
+        *      The allowed bandwidth speed are 640 Kbps, 1 Mbps, 2 Mbps and 4 Mbps.
+        *      </p>
+        *      @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 <tt>p</tt>.
+        *      @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 <tt>newer_distr</tt>
+        *      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 (file)
index 0000000..d0e92d5
--- /dev/null
@@ -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 <tt>peerset</tt>
+ *     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 <tt>peerset</tt> 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 (file)
index 0000000..1da537a
--- /dev/null
@@ -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.
+       * <p>
+       * The available identifiers for event type are:<br/>
+       * <ul>
+       *  <li>1 is KEEP_ALIVE message</li>
+       *  <li>2 is CHOKE message</li>
+       *  <li>3 is UNCHOKE message</li>
+       *  <li>4 is INTERESTED message</li>
+       *  <li>5 is NOT_INTERESTED message</li>
+       *  <li>6 is HAVE message</li>
+       *  <li>7 is BITFIELD message</li>
+       *  <li>8 is REQUEST message</li>
+       *  <li>9 is PIECE message</li>
+       *  <li>10 is CANCEL message</li>
+       *  <li>11 is TRACKER message</li>
+       *  <li>12 is PEERSET message</li>
+       *  <li>13 is CHOKE_TIME event</li>
+       *  <li>14 is OPTUNCHK_TIME event</li>
+       *  <li>15 is ANTISNUB_TIME event</li>
+       *  <li>16 is CHECKALIVE_TIME event</li>
+       *  <li>17 is TRACKERALIVE_TIME event</li>
+       *  <li>18 is DOWNLOAD_COMPLETED event</li>
+       *</ul></p>
+       */
+       protected int type;
+       
+       public SimpleEvent(){
+       }
+       
+       /**
+     * Initializes the type of the event.
+        * @param type The identifier of the type of the event
+        */
+       public SimpleEvent(int type){
+               this.type = type;
+       }
+       
+       /**
+        * Gets the type of the event.
+        * @return The type of the current event.
+        */
+       public int getType(){
+               return this.type;       
+       }
+}
+
+
diff --git a/contrib/psg/src/example/bittorrent/SimpleMsg.java b/contrib/psg/src/example/bittorrent/SimpleMsg.java
new file mode 100644 (file)
index 0000000..cf9436e
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * 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 defines a simple message.
+ * A simple message has its type and the reference of the sender node.
+ * @see SimpleEvent
+ */
+public class SimpleMsg extends SimpleEvent {
+       
+       /**
+       * The sender of the message.
+       */
+       protected Node sender;
+       
+       public SimpleMsg(){
+       }
+       
+       /**
+        * Initializes the simple message with its type and sender.
+        * @param type The identifier of the type of the message
+        * @param sender The sender of the message
+        */
+       public SimpleMsg(int type, Node sender){
+               super.type = type;
+               this.sender = sender;
+       }
+       
+       /**
+     * Gets the sender of the message.
+        * @return The sender of the message.
+        */
+       public Node getSender(){
+               return this.sender;     
+       }
+}
diff --git a/contrib/psg/src/example/chord/ChordInitializer.java b/contrib/psg/src/example/chord/ChordInitializer.java
new file mode 100644 (file)
index 0000000..799b0d7
--- /dev/null
@@ -0,0 +1,72 @@
+package example.chord;\r
+\r
+import java.math.BigInteger;\r
+import java.util.Random;\r
+import peersim.config.Configuration;\r
+import peersim.core.CommonState;\r
+import peersim.core.Network;\r
+import peersim.core.Node;\r
+import peersim.dynamics.NodeInitializer;\r
+\r
+public class ChordInitializer implements NodeInitializer {\r
+\r
+       private static final String PAR_PROT = "protocol";\r
+\r
+       private int pid = 0;\r
+\r
+       private ChordProtocol cp;\r
+\r
+       public ChordInitializer(String prefix) {\r
+               pid = Configuration.getPid(prefix + "." + PAR_PROT);\r
+       }\r
+\r
+       public void initialize(Node n) {\r
+               cp = (ChordProtocol) n.getProtocol(pid);\r
+               join(n);\r
+       }\r
+\r
+       public void join(Node myNode) {\r
+               Random generator = new Random();\r
+               //Random generator = new Random(1234567890);\r
+               cp.predecessor = null;\r
+               // search a node to join\r
+               Node n;\r
+               do {\r
+                       n = Network.get(generator.nextInt(Network.size()));\r
+               } while (n == null || n.isUp() == false);\r
+               cp.m = ((ChordProtocol) n.getProtocol(pid)).m;\r
+               cp.chordId = new BigInteger(cp.m, CommonState.r);\r
+               ChordProtocol cpRemote = (ChordProtocol) n.getProtocol(pid);\r
+\r
+               Node successor = cpRemote.find_successor(cp.chordId);\r
+               cp.fails = 0;\r
+               cp.stabilizations = 0;\r
+               cp.varSuccList = cpRemote.varSuccList;\r
+               cp.varSuccList = 0;\r
+               cp.succLSize = cpRemote.succLSize;\r
+               cp.successorList = new Node[cp.succLSize];\r
+               cp.successorList[0] = successor;\r
+               cp.fingerTable = new Node[cp.m];\r
+               long succId = 0;\r
+               BigInteger lastId = ((ChordProtocol) Network.get(Network.size() - 1)\r
+                               .getProtocol(pid)).chordId;\r
+               do {\r
+                       cp.stabilizations++;\r
+                       succId = cp.successorList[0].getID();\r
+                       cp.stabilize(myNode);\r
+                       if (((ChordProtocol) cp.successorList[0].getProtocol(pid)).chordId\r
+                                       .compareTo(cp.chordId) < 0) {\r
+                               cp.successorList[0] = ((ChordProtocol) cp.successorList[0]\r
+                                               .getProtocol(pid)).find_successor(cp.chordId);\r
+                       }\r
+                       // controllo di non essere l'ultimo elemento della rete\r
+                       if (cp.chordId.compareTo(lastId) > 0) {\r
+                               cp.successorList[0] = Network.get(0);\r
+                               break;\r
+                       }\r
+               } while (cp.successorList[0].getID() != succId\r
+                               || ((ChordProtocol) cp.successorList[0].getProtocol(pid)).chordId\r
+                                               .compareTo(cp.chordId) < 0);\r
+               cp.fixFingers();\r
+       }\r
+}\r
diff --git a/contrib/psg/src/example/chord/ChordMessage.java b/contrib/psg/src/example/chord/ChordMessage.java
new file mode 100644 (file)
index 0000000..f87fafb
--- /dev/null
@@ -0,0 +1,12 @@
+/**\r
+ * \r
+ */\r
+package example.chord;\r
+\r
+/**\r
+ * @author Andrea\r
+ * \r
+ */\r
+public interface ChordMessage {\r
+\r
+}\r
diff --git a/contrib/psg/src/example/chord/ChordProtocol.java b/contrib/psg/src/example/chord/ChordProtocol.java
new file mode 100644 (file)
index 0000000..485c3ba
--- /dev/null
@@ -0,0 +1,358 @@
+/**\r
+ * \r
+ */\r
+package example.chord;\r
+\r
+import peersim.config.Configuration;\r
+import peersim.core.CommonState;\r
+import peersim.core.Network;\r
+import peersim.core.Node;\r
+import peersim.edsim.EDProtocol;\r
+import peersim.transport.Transport;\r
+\r
+import java.math.*;\r
+\r
+import org.simgrid.msg.Host;\r
+import org.simgrid.msg.Msg;\r
+\r
+/**\r
+ * @author Andrea\r
+ * \r
+ */\r
+public class ChordProtocol implements EDProtocol {\r
+\r
+       private static final String PAR_TRANSPORT = "transport";\r
+\r
+       private Parameters p;\r
+\r
+       private int[] lookupMessage;\r
+\r
+       public int index = 0;\r
+\r
+       public Node predecessor;\r
+\r
+       public Node[] fingerTable;\r
+\r
+       public Node[] successorList;\r
+\r
+       public BigInteger chordId;\r
+\r
+       public int m;\r
+\r
+       public int succLSize;\r
+\r
+       public String prefix;\r
+\r
+       private int next = 0;\r
+\r
+       // campo x debug\r
+       private int currentNode = 0;\r
+\r
+       public int varSuccList = 0;\r
+\r
+       public int stabilizations = 0;\r
+\r
+       public int fails = 0;\r
+\r
+       /**\r
+        * \r
+        */\r
+       public ChordProtocol(String prefix) {\r
+               this.prefix = prefix;\r
+               lookupMessage = new int[1];\r
+               lookupMessage[0] = 0;\r
+               p = new Parameters();\r
+               p.tid = Configuration.getPid(prefix + "." + PAR_TRANSPORT);\r
+       }\r
+\r
+       /*\r
+        * (non-Javadoc)\r
+        * \r
+        * @see peersim.edsim.EDProtocol#processEvent(peersim.core.Node, int,\r
+        * java.lang.Object)\r
+        */\r
+       public void processEvent(Node node, int pid, Object event) {\r
+               // processare le richieste a seconda della routing table del nodo\r
+               p.pid = pid;\r
+               // currentNode = node.getIndex();\r
+               currentNode = (int) node.getID();\r
+               if (event.getClass() == LookUpMessage.class) {\r
+                       LookUpMessage message = (LookUpMessage) event;\r
+                       message.increaseHopCounter();\r
+                       BigInteger target = message.getTarget();\r
+                       Transport t = (Transport) node.getProtocol(p.tid);\r
+                       Node n = message.getSender();\r
+                       System.out.println("R process " + "at time="\r
+                                       + CommonState.getTime() + " to dest:" + currentNode\r
+                                       + " from src:" + n.getID() + " message: ("\r
+                                       + message.getSender().getID() + ";" + message.getTarget()\r
+                                       + ")");\r
+                       if (target == ((ChordProtocol) node.getProtocol(pid)).chordId) {\r
+                               // mandare mess di tipo final\r
+                               Object msg = new FinalMessage(message.getHopCounter());\r
+                               System.out.println("S Final Message " + "at time="\r
+                                               + CommonState.getTime() + " from src:" + node.getID()\r
+                                               + " to dest:" + n.getID() + " message: "\r
+                                               + message.getHopCounter() + " HopCounter");\r
+                               t.send(node, n, msg, pid);\r
+\r
+                       }\r
+                       if (target != ((ChordProtocol) node.getProtocol(pid)).chordId) {\r
+                               // funzione lookup sulla fingertabable\r
+                               Node dest = find_successor(target);\r
+                               if (dest.isUp() == false) {\r
+                                       do {\r
+                                               varSuccList = 0;\r
+                                               stabilize(node);\r
+                                               stabilizations++;\r
+                                               fixFingers();\r
+                                               dest = find_successor(target);\r
+                                       } while (dest.isUp() == false);\r
+                               }\r
+                               if (dest.getID() == successorList[0].getID()\r
+                                               && (target.compareTo(((ChordProtocol) dest\r
+                                                               .getProtocol(p.pid)).chordId) < 0)) {\r
+                                       fails++;\r
+                               } else {\r
+                                       System.out.println("S process " + "at time="\r
+                                                       + CommonState.getTime() + " from src:"\r
+                                                       + node.getID() + " to dest:" + dest.getID()\r
+                                                       + " message: (" + message.getSender().getID() + ";"\r
+                                                       + message.getTarget() + ")");\r
+                                       // t.send(message.getSender(), dest, message, pid);\r
+                                       t.send(node, dest, message, pid);\r
+\r
+                               }\r
+                       }\r
+               }\r
+               if (event.getClass() == FinalMessage.class) {\r
+                       FinalMessage message = (FinalMessage) event;\r
+                       System.out.println("R Final Message " + "at time="\r
+                                       + CommonState.getTime() + " to dest:" + node.getID()+"\n");\r
+                       lookupMessage = new int[index + 1];\r
+                       lookupMessage[index] = message.getHopCounter();\r
+                       index++;\r
+               }\r
+       }\r
+\r
+       public Object clone() {\r
+               ChordProtocol cp = new ChordProtocol(prefix);\r
+               String val = BigInteger.ZERO.toString();\r
+               cp.chordId = new BigInteger(val);\r
+               cp.fingerTable = new Node[m];\r
+               cp.successorList = new Node[succLSize];\r
+               cp.currentNode = 0;\r
+               return cp;\r
+       }\r
+\r
+       public int[] getLookupMessage() {\r
+               return lookupMessage;\r
+       }\r
+\r
+       public void stabilize(Node myNode) {\r
+               try {\r
+                       Node node = ((ChordProtocol) successorList[0].getProtocol(p.pid)).predecessor;\r
+                       if (node != null) {\r
+                               if (this.chordId == ((ChordProtocol) node.getProtocol(p.pid)).chordId)\r
+                                       return;\r
+                               BigInteger remoteID = ((ChordProtocol) node.getProtocol(p.pid)).chordId;\r
+                               if (idInab(\r
+                                               remoteID,\r
+                                               chordId,\r
+                                               ((ChordProtocol) successorList[0].getProtocol(p.pid)).chordId))\r
+                                       successorList[0] = node;\r
+                               ((ChordProtocol) successorList[0].getProtocol(p.pid))\r
+                                               .notify(myNode);\r
+                       }\r
+                       updateSuccessorList();\r
+               } catch (Exception e1) {\r
+                       e1.printStackTrace();\r
+                       updateSuccessor();\r
+               }\r
+       }\r
+\r
+       private void updateSuccessorList() throws Exception {\r
+               try {\r
+                       while (successorList[0] == null || successorList[0].isUp() == false) {\r
+                               updateSuccessor();\r
+                       }\r
+                       System.arraycopy(\r
+                                       ((ChordProtocol) successorList[0].getProtocol(p.pid)).successorList,\r
+                                       0, successorList, 1, succLSize - 2);\r
+               } catch (Exception e) {\r
+                       e.printStackTrace();\r
+               }\r
+       }\r
+\r
+       public void notify(Node node) throws Exception {\r
+               BigInteger nodeId = ((ChordProtocol) node.getProtocol(p.pid)).chordId;\r
+               if ((predecessor == null)\r
+                               || (idInab(\r
+                                               nodeId,\r
+                                               ((ChordProtocol) predecessor.getProtocol(p.pid)).chordId,\r
+                                               this.chordId))) {\r
+                       predecessor = node;\r
+               }\r
+       }\r
+\r
+       private void updateSuccessor() {\r
+               boolean searching = true;\r
+               while (searching) {\r
+                       try {\r
+                               Node node = successorList[varSuccList];\r
+                               varSuccList++;\r
+                               successorList[0] = node;\r
+                               if (successorList[0] == null\r
+                                               || successorList[0].isUp() == false) {\r
+                                       if (varSuccList >= succLSize - 1) {\r
+                                               searching = false;\r
+                                               varSuccList = 0;\r
+                                       } else\r
+                                               updateSuccessor();\r
+                               }\r
+                               updateSuccessorList();\r
+                               searching = false;\r
+                       } catch (Exception e) {\r
+                               e.printStackTrace();\r
+                       }\r
+               }\r
+       }\r
+\r
+       private boolean idInab(BigInteger id, BigInteger a, BigInteger b) {\r
+               if ((a.compareTo(id) == -1) && (id.compareTo(b) == -1)) {\r
+                       return true;\r
+               }\r
+               return false;\r
+       }\r
+\r
+       public Node find_successor(BigInteger id) {\r
+               try {\r
+                       if (successorList[0] == null || successorList[0].isUp() == false) {\r
+                               updateSuccessor();\r
+                       }\r
+                       if (idInab(\r
+                                       id,\r
+                                       this.chordId,\r
+                                       ((ChordProtocol) successorList[0].getProtocol(p.pid)).chordId)) {\r
+                               return successorList[0];\r
+                       } else {\r
+                               Node tmp = closest_preceding_node(id);\r
+                               return tmp;\r
+                       }\r
+               } catch (Exception e) {\r
+                       e.printStackTrace();\r
+               }\r
+               return successorList[0];\r
+       }\r
+\r
+       private Node closest_preceding_node(BigInteger id) {\r
+               for (int i = m; i > 0; i--) {\r
+                       try {\r
+                               if (fingerTable[i - 1] == null\r
+                                               || fingerTable[i - 1].isUp() == false) {\r
+                                       continue;\r
+                               }\r
+                               BigInteger fingerId = ((ChordProtocol) (fingerTable[i - 1]\r
+                                               .getProtocol(p.pid))).chordId;\r
+                               if ((idInab(fingerId, this.chordId, id))\r
+                                               || (id.compareTo(fingerId) == 0)) {\r
+                                       return fingerTable[i - 1];\r
+                               }\r
+                               if (fingerId.compareTo(this.chordId) == -1) {\r
+                                       // sono nel caso in cui ho fatto un giro della rete\r
+                                       // circolare\r
+                                       if (idInab(id, fingerId, this.chordId)) {\r
+                                               return fingerTable[i - 1];\r
+                                       }\r
+                               }\r
+                               if ((id.compareTo(fingerId) == -1)\r
+                                               && (id.compareTo(this.chordId) == -1)) {\r
+                                       if (i == 1)\r
+                                               return successorList[0];\r
+                                       BigInteger lowId = ((ChordProtocol) fingerTable[i - 2]\r
+                                                       .getProtocol(p.pid)).chordId;\r
+                                       if (idInab(id, lowId, fingerId))\r
+                                               return fingerTable[i - 2];\r
+                                       else if (fingerId.compareTo(this.chordId) == -1)\r
+                                               continue;\r
+                                       else if (fingerId.compareTo(this.chordId) == 1)\r
+                                               return fingerTable[i - 1];\r
+                               }\r
+                       } catch (Exception e) {\r
+                               e.printStackTrace();\r
+                       }\r
+               }\r
+               if (fingerTable[m - 1] == null)\r
+                       return successorList[0];\r
+               return successorList[0];\r
+       }\r
+\r
+       // debug function\r
+       private void printFingers() {\r
+               for (int i = fingerTable.length - 1; i > 0; i--) {\r
+                       if (fingerTable[i] == null) {\r
+                               System.out.println("Finger " + i + " is null");\r
+                               continue;\r
+                       }\r
+                       if ((((ChordProtocol) fingerTable[i].getProtocol(p.pid)).chordId)\r
+                                       .compareTo(this.chordId) == 0)\r
+                               break;\r
+                       System.out\r
+                                       .println("Finger["\r
+                                                       + i\r
+                                                       + "] = "\r
+                                                       + fingerTable[i].getIndex()\r
+                                                       + " chordId "\r
+                                                       + ((ChordProtocol) fingerTable[i]\r
+                                                                       .getProtocol(p.pid)).chordId);\r
+               }\r
+       }\r
+\r
+       public void fixFingers() {\r
+               if (next >= m - 1)\r
+                       next = 0;\r
+               if (fingerTable[next] != null && fingerTable[next].isUp()) {\r
+                       next++;\r
+                       return;\r
+               }\r
+               BigInteger base;\r
+               if (next == 0)\r
+                       base = BigInteger.ONE;\r
+               else {\r
+                       base = BigInteger.valueOf(2);\r
+                       for (int exp = 1; exp < next; exp++) {\r
+                               base = base.multiply(BigInteger.valueOf(2));\r
+                       }\r
+               }\r
+               BigInteger pot = this.chordId.add(base);\r
+               BigInteger idFirst = ((ChordProtocol) Network.get(0).getProtocol(p.pid)).chordId;\r
+               BigInteger idLast = ((ChordProtocol) Network.get(Network.size() - 1)\r
+                               .getProtocol(p.pid)).chordId;\r
+               if (pot.compareTo(idLast) == 1) {\r
+                       pot = (pot.mod(idLast));\r
+                       if (pot.compareTo(this.chordId) != -1) {\r
+                               next++;\r
+                               return;\r
+                       }\r
+                       if (pot.compareTo(idFirst) == -1) {\r
+                               this.fingerTable[next] = Network.get(Network.size() - 1);\r
+                               next++;\r
+                               return;\r
+                       }\r
+               }\r
+               do {\r
+                       fingerTable[next] = ((ChordProtocol) successorList[0]\r
+                                       .getProtocol(p.pid)).find_successor(pot);\r
+                       pot = pot.subtract(BigInteger.ONE);\r
+                       ((ChordProtocol) successorList[0].getProtocol(p.pid)).fixFingers();\r
+               } while (fingerTable[next] == null || fingerTable[next].isUp() == false);\r
+               next++;\r
+       }\r
+\r
+       /**\r
+        */\r
+       public void emptyLookupMessage() {\r
+               index = 0;\r
+               this.lookupMessage = new int[0];\r
+       }\r
+}\r
diff --git a/contrib/psg/src/example/chord/CreateNw.java b/contrib/psg/src/example/chord/CreateNw.java
new file mode 100644 (file)
index 0000000..9268653
--- /dev/null
@@ -0,0 +1,148 @@
+/**\r
+ * \r
+ */\r
+package example.chord;\r
+\r
+import peersim.core.*;\r
+import peersim.config.Configuration;\r
+import java.math.*;\r
+\r
+/**\r
+ * @author Andrea\r
+ * \r
+ */\r
+public class CreateNw implements Control {\r
+\r
+       private int pid = 0;\r
+\r
+       private static final String PAR_IDLENGTH = "idLength";\r
+\r
+       private static final String PAR_PROT = "protocol";\r
+\r
+       private static final String PAR_SUCCSIZE = "succListSize";\r
+\r
+       int idLength = 0;\r
+\r
+       int successorLsize = 0;\r
+\r
+       int fingSize = 0;\r
+       //campo x debug\r
+       boolean verbose = false;\r
+\r
+       /**\r
+        * \r
+        */\r
+       public CreateNw(String prefix) {\r
+               pid = Configuration.getPid(prefix + "." + PAR_PROT);\r
+               idLength = Configuration.getInt(prefix + "." + PAR_IDLENGTH); \r
+               successorLsize = Configuration.getInt(prefix + "." + PAR_SUCCSIZE); \r
+       }\r
+\r
+       /*\r
+        * (non-Javadoc)\r
+        * \r
+        * @see peersim.core.Control#execute()\r
+        */\r
+\r
+       public boolean execute() {\r
+               for (int i = 0; i < Network.size(); i++) {\r
+                       Node node = (Node) Network.get(i);\r
+                       ChordProtocol cp = (ChordProtocol) node.getProtocol(pid);\r
+                       cp.m = idLength;\r
+                       cp.succLSize = successorLsize;\r
+                       cp.varSuccList = 0;\r
+                       cp.chordId = new BigInteger(idLength, CommonState.r);\r
+                       cp.fingerTable = new Node[idLength];\r
+                       cp.successorList = new Node[successorLsize];\r
+               }\r
+               NodeComparator nc = new NodeComparator(pid);\r
+               Network.sort(nc);\r
+               createFingerTable();\r
+               return false;\r
+       }\r
+\r
+       public Node findId(BigInteger id, int nodeOne, int nodeTwo) {\r
+               if (nodeOne >= (nodeTwo - 1)) \r
+                       return Network.get(nodeOne);\r
+               int middle = (nodeOne + nodeTwo) / 2;\r
+               if (((middle) >= Network.size() - 1))\r
+                       System.out.print("ERROR: Middle is bigger than Network.size");\r
+               if (((middle) <= 0))\r
+                       return Network.get(0);\r
+               try {\r
+                       BigInteger newId = ((ChordProtocol) ((Node) Network.get(middle))\r
+                                       .getProtocol(pid)).chordId;\r
+                       BigInteger lowId;\r
+                       if (middle > 0)\r
+                               lowId = ((ChordProtocol) ((Node) Network.get(middle - 1))\r
+                                               .getProtocol(pid)).chordId;\r
+                       else\r
+                               lowId = newId;\r
+                       BigInteger highId = ((ChordProtocol) ((Node) Network\r
+                                       .get(middle + 1)).getProtocol(pid)).chordId;\r
+                       if (id.compareTo(newId) == 0\r
+                                       || ((id.compareTo(newId) == 1) && (id.compareTo(highId) == -1))) {\r
+                               return Network.get(middle);\r
+                       }\r
+                       if ((id.compareTo(newId) == -1) && (id.compareTo(lowId) == 1)) {\r
+                               if (middle > 0)\r
+                                       return Network.get(middle - 1);\r
+                               else\r
+                                       return Network.get(0);\r
+                       }\r
+                       if (id.compareTo(newId) == -1) {\r
+                               return findId(id, nodeOne, middle);\r
+                       } else if (id.compareTo(newId) == 1) {\r
+                               return findId(id, middle, nodeTwo);\r
+                       }\r
+                       return null;\r
+               } catch (Exception e) {\r
+                       e.printStackTrace();\r
+                       return null;\r
+               }\r
+       }\r
+\r
+       public void createFingerTable() {\r
+               BigInteger idFirst = ((ChordProtocol) Network.get(0).getProtocol(pid)).chordId;\r
+               BigInteger idLast = ((ChordProtocol) Network.get(Network.size() - 1)\r
+                               .getProtocol(pid)).chordId;\r
+               for (int i = 0; i < Network.size(); i++) {\r
+                       Node node = (Node) Network.get(i);\r
+                       ChordProtocol cp = (ChordProtocol) node.getProtocol(pid);\r
+                       for (int a = 0; a < successorLsize; a++) {\r
+                               if (a + i < (Network.size() - 1))\r
+                                       cp.successorList[a] = Network.get(a + i + 1);\r
+                               else\r
+                                       cp.successorList[a] = Network.get(a);\r
+                       }\r
+                       if (i > 0)\r
+                               cp.predecessor = (Node) Network.get(i - 1);\r
+                       else\r
+                               cp.predecessor = (Node) Network.get(Network.size() - 1);\r
+                       int j = 0;\r
+                       for (j = 0; j < idLength; j++) {\r
+                               BigInteger base;\r
+                               if (j == 0)\r
+                                       base = BigInteger.ONE;\r
+                               else {\r
+                                       base = BigInteger.valueOf(2);\r
+                                       for (int exp = 1; exp < j; exp++) {\r
+                                               base = base.multiply(BigInteger.valueOf(2));\r
+                                       }\r
+                               }\r
+                               BigInteger pot = cp.chordId.add(base);\r
+                               if (pot.compareTo(idLast) == 1) {\r
+                                       pot = (pot.mod(idLast));\r
+                                       if (pot.compareTo(cp.chordId) != -1) {\r
+                                               break;\r
+                                       }\r
+                                       if (pot.compareTo(idFirst) == -1) {\r
+                                               cp.fingerTable[j] = Network.get(Network.size() - 1);\r
+                                               continue;\r
+                                       }\r
+                               }\r
+                               cp.fingerTable[j] = findId(pot, 0, Network.size() - 1);\r
+                       }\r
+               }\r
+       }\r
+}\r
diff --git a/contrib/psg/src/example/chord/FinalMessage.java b/contrib/psg/src/example/chord/FinalMessage.java
new file mode 100644 (file)
index 0000000..847dba9
--- /dev/null
@@ -0,0 +1,14 @@
+package example.chord;\r
+\r
+public class FinalMessage implements ChordMessage {\r
+\r
+       private int hopCounter = 0;\r
+\r
+       public FinalMessage(int hopCounter) {\r
+               this.hopCounter = hopCounter;\r
+       }\r
+\r
+       public int getHopCounter() {\r
+               return hopCounter;\r
+       }\r
+}\r
diff --git a/contrib/psg/src/example/chord/LookUpMessage.java b/contrib/psg/src/example/chord/LookUpMessage.java
new file mode 100644 (file)
index 0000000..091089e
--- /dev/null
@@ -0,0 +1,44 @@
+package example.chord;\r
+\r
+import java.math.*;\r
+import peersim.core.*;\r
+\r
+public class LookUpMessage implements ChordMessage {\r
+\r
+       private Node sender;\r
+\r
+       private BigInteger targetId;\r
+\r
+       private int hopCounter = -1;\r
+\r
+       public LookUpMessage(Node sender, BigInteger targetId) {\r
+               this.sender = sender;\r
+               this.targetId = targetId;\r
+       }\r
+\r
+       public void increaseHopCounter() {\r
+               hopCounter++;\r
+       }\r
+\r
+       /**\r
+        * @return the senderId\r
+        */\r
+       public Node getSender() {\r
+               return sender;\r
+       }\r
+\r
+       /**\r
+        * @return the target\r
+        */\r
+       public BigInteger getTarget() {\r
+               return targetId;\r
+       }\r
+\r
+       /**\r
+        * @return the hopCounter\r
+        */\r
+       public int getHopCounter() {\r
+               return hopCounter;\r
+       }\r
+\r
+}\r
diff --git a/contrib/psg/src/example/chord/MessageCounterObserver.java b/contrib/psg/src/example/chord/MessageCounterObserver.java
new file mode 100644 (file)
index 0000000..dbcbb8f
--- /dev/null
@@ -0,0 +1,108 @@
+/**\r
+ * \r
+ */\r
+package example.chord;\r
+\r
+import java.util.ArrayList;\r
+import peersim.core.Control;\r
+import peersim.core.Network;\r
+import peersim.config.Configuration;\r
+\r
+/**\r
+ * @author Andrea\r
+ * \r
+ */\r
+public class MessageCounterObserver implements Control {\r
+\r
+       private static final String PAR_PROT = "protocol";\r
+\r
+       private final String prefix;\r
+\r
+       private final int pid;\r
+\r
+       /**\r
+        * \r
+        */\r
+       public MessageCounterObserver(String prefix) {\r
+               this.prefix = prefix;\r
+               this.pid = Configuration.getPid(prefix + "." + PAR_PROT);\r
+       }\r
+\r
+       /*\r
+        * (non-Javadoc)\r
+        * \r
+        * @see peersim.core.Control#execute()\r
+        */\r
+       public boolean execute() {\r
+               int size = Network.size();\r
+               int totalStab = 0;\r
+               int totFails = 0;\r
+               ArrayList hopCounters = new ArrayList(); // struttura dati che\r
+                                                                                                       // memorizza gli hop di\r
+                                                                                                       // tutti i mess mandati\r
+               hopCounters.clear();\r
+               int max = 0;\r
+               int min = Integer.MAX_VALUE;\r
+               for (int i = 0; i < size; i++) {\r
+                       ChordProtocol cp = (ChordProtocol) Network.get(i).getProtocol(pid);\r
+                       // trovare tutti gli hopCOunter dei messaggi lookup mandati\r
+                       int[] counters = new int[cp.getLookupMessage().length];\r
+                       System.arraycopy(cp.getLookupMessage(), 0, counters, 0, cp\r
+                                       .getLookupMessage().length);\r
+                       totalStab = totalStab + cp.stabilizations;\r
+                       totFails = totFails + cp.fails;\r
+                       cp.stabilizations = 0;\r
+                       cp.fails = 0;\r
+                       int maxNew = maxArray(counters, cp.index);\r
+                       if (maxNew > max)\r
+                               max = maxNew;\r
+                       if (cp.index != 0) {\r
+                               for (int j = 0; j < cp.index; j++)\r
+                                       hopCounters.add(counters[j]);\r
+                               int minNew = minArray(counters, cp.index);\r
+                               if (minNew < min)\r
+                                       min = minNew;\r
+                       }\r
+                       cp.emptyLookupMessage();\r
+               }\r
+               double media = meanCalculator(hopCounters);\r
+               if (media > 0)\r
+                       System.out.println("Mean:  " + media + " Max Value: " + max\r
+                                       + " Min Value: " + min + " # Observations: "\r
+                                       + hopCounters.size());\r
+               System.out.println("     # Stabilizations: " + totalStab + " # Failures: "\r
+                               + totFails);\r
+               System.out.println("");\r
+               return false;\r
+       }\r
+\r
+       private double meanCalculator(ArrayList list) {\r
+               int lenght = list.size();\r
+               if (lenght == 0)\r
+                       return 0;\r
+               int sum = 0;\r
+               for (int i = 0; i < lenght; i++) {\r
+                       sum = sum + ((Integer) list.get(i)).intValue();\r
+               }\r
+               double mean = sum / lenght;\r
+               return mean;\r
+       }\r
+\r
+       private int maxArray(int[] array, int dim) {\r
+               int max = 0;\r
+               for (int j = 0; j < dim; j++) {\r
+                       if (array[j] > max)\r
+                               max = array[j];\r
+               }\r
+               return max;\r
+       }\r
+\r
+       private int minArray(int[] array, int dim) {\r
+               int min = 0;\r
+               for (int j = 0; j < dim; j++) {\r
+                       if (array[j] < min)\r
+                               min = array[j];\r
+               }\r
+               return min;\r
+       }\r
+}\r
diff --git a/contrib/psg/src/example/chord/NodeComparator.java b/contrib/psg/src/example/chord/NodeComparator.java
new file mode 100644 (file)
index 0000000..def16dc
--- /dev/null
@@ -0,0 +1,21 @@
+package example.chord;\r
+\r
+import java.util.Comparator;\r
+import java.math.*;\r
+import peersim.core.*;\r
+\r
+public class NodeComparator implements Comparator {\r
+\r
+       public int pid = 0;\r
+\r
+       public NodeComparator(int pid) {\r
+               this.pid = pid;\r
+       }\r
+\r
+       public int compare(Object arg0, Object arg1) {\r
+               BigInteger one = ((ChordProtocol) ((Node) arg0).getProtocol(pid)).chordId;\r
+               BigInteger two = ((ChordProtocol) ((Node) arg1).getProtocol(pid)).chordId;\r
+               return one.compareTo(two);\r
+       }\r
+\r
+}\r
diff --git a/contrib/psg/src/example/chord/Parameters.java b/contrib/psg/src/example/chord/Parameters.java
new file mode 100644 (file)
index 0000000..d32d82f
--- /dev/null
@@ -0,0 +1,7 @@
+package example.chord;\r
+\r
+public class Parameters {\r
+       int pid;\r
+\r
+       int tid;\r
+}\r
diff --git a/contrib/psg/src/example/chord/TrafficGenerator.java b/contrib/psg/src/example/chord/TrafficGenerator.java
new file mode 100644 (file)
index 0000000..09c5854
--- /dev/null
@@ -0,0 +1,54 @@
+/**\r
+ * \r
+ */\r
+package example.chord;\r
+\r
+import org.simgrid.msg.Host;\r
+\r
+import peersim.core.*;\r
+import peersim.config.Configuration;\r
+import peersim.edsim.EDSimulator;\r
+import psgsim.PSGSimulator;\r
+\r
+/**\r
+ * @author Andrea\r
+ * \r
+ */\r
+public class TrafficGenerator implements Control {\r
+\r
+       private static final String PAR_PROT = "protocol";\r
+\r
+       private final int pid;\r
+\r
+       /**\r
+        * \r
+        */\r
+       public TrafficGenerator(String prefix) {\r
+               pid = Configuration.getPid(prefix + "." + PAR_PROT);\r
+       }\r
+\r
+       /*\r
+        * (non-Javadoc)\r
+        * \r
+        * @see peersim.core.Control#execute()\r
+        */\r
+       public boolean execute() {\r
+               int size = Network.size();\r
+               Node sender, target;\r
+               int i = 0;\r
+               do {\r
+                       i++;\r
+                       sender = Network.get(CommonState.r.nextInt(size));\r
+                       target = Network.get(CommonState.r.nextInt(size));\r
+               } while (sender == null || sender.isUp() == false || target == null\r
+                               || target.isUp() == false);\r
+               LookUpMessage message = new LookUpMessage(sender,\r
+                               ((ChordProtocol) target.getProtocol(pid)).chordId);\r
+               System.out.println("TrafficGenerator at time "+CommonState.getTime()+" Node:"\r
+                               + message.getSender().getID() +" target "+target.getID() + " pid:"\r
+                               + pid);\r
+               EDSimulator.add(10, message, sender, pid);\r
+               return false;\r
+       }\r
+\r
+}\r
diff --git a/contrib/psg/src/example/edaggregation/AverageED.java b/contrib/psg/src/example/edaggregation/AverageED.java
new file mode 100644 (file)
index 0000000..c5f3358
--- /dev/null
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 2003 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 example.edaggregation;
+
+import peersim.vector.SingleValueHolder;
+import peersim.config.*;
+import peersim.core.*;
+import peersim.transport.Transport;
+import peersim.cdsim.CDProtocol;
+import peersim.edsim.EDProtocol;
+
+/**
+ * Event driven version of epidemic averaging.
+ */
+public class AverageED extends SingleValueHolder implements CDProtocol,
+               EDProtocol {
+
+       // --------------------------------------------------------------------------
+       // Initialization
+       // --------------------------------------------------------------------------
+
+       /**
+        * @param prefix
+        *            string prefix for config properties
+        */
+       public AverageED(String prefix) {
+               super(prefix);
+       }
+
+       // --------------------------------------------------------------------------
+       // methods
+       // --------------------------------------------------------------------------
+
+       /**
+        * This is the standard method the define periodic activity. The frequency
+        * of execution of this method is defined by a
+        * {@link peersim.edsim.CDScheduler} component in the configuration.
+        */
+       public void nextCycle(Node node, int pid) {
+               Linkable linkable = (Linkable) node.getProtocol(FastConfig
+                               .getLinkable(pid));
+               if (linkable.degree() > 0) {
+                       int degree=linkable.degree();
+                       int i=CommonState.r.nextInt(degree);            
+                       Node peern = linkable.getNeighbor(i);
+                       System.out.println("Pid of the protocol: "+pid);
+                       System.out.println("Time="+CommonState.getTime()+" degree="+degree+" i="+i+" peernID="+peern.getID()+" peernIndex="+peern.getIndex());
+                       if (!peern.isUp())
+                               return;
+                       AverageMessage ob=new AverageMessage(value, node);
+                       System.out.println("NextCycle\t"+"\t Time: " + CommonState.getTime()+ "\t src: " + node.getID() + "\t dst: " + peern.getID()+"\t msg:"+ob.value);
+                       ((Transport) node.getProtocol(FastConfig.getTransport(pid))).send(
+                                       node, peern, ob, pid);
+               }
+       }
+
+       // --------------------------------------------------------------------------
+
+       /**
+        * This is the standard method to define to process incoming messages.
+        */
+       public void processEvent(Node node, int pid, Object event) {
+
+               AverageMessage aem = (AverageMessage) event;
+
+               AverageMessage ob=null;
+               if (aem.sender != null){
+                       System.out.println("ProcessEventR\t"+"\t Time: " + CommonState.getTime() + "\t src: " + aem.sender.getID() + "\t dst: " + node.getID()+"\t msg:"+aem.value);
+                       ob=new AverageMessage(value, null);
+                       System.out.println("ProcessEventS\t"+"\t Time: " + CommonState.getTime()+ "\t src: " + node.getID() + "\t dst: " + aem.sender.getID()+"\t msg:"+ob.value);
+                       ((Transport) node.getProtocol(FastConfig.getTransport(pid))).send(
+                                       node, aem.sender, ob, pid);
+       } else {
+               System.out.println("ProcessEventR\t"+"\t Time: " +CommonState.getTime() + "\t src: " + "NULL" + "\t dst: " + node.getID()+"\t msg:"+aem.value);
+       }
+               value = (value + aem.value) / 2;
+       }
+
+}
+
+// --------------------------------------------------------------------------
+// --------------------------------------------------------------------------
+
+/**
+ * The type of a message. It contains a value of type double and the sender node
+ * of type {@link peersim.core.Node}.
+ */
+class AverageMessage {
+
+       final double value;
+       /**
+        * If not null, this has to be answered, otherwise this is the answer.
+        */
+       final Node sender;
+
+       public AverageMessage(double value, Node sender) {
+               this.value = value;
+               this.sender = sender;
+       }
+}
\ No newline at end of file
diff --git a/contrib/psg/src/example/symphony/AdapterIterableNetwork.java b/contrib/psg/src/example/symphony/AdapterIterableNetwork.java
new file mode 100644 (file)
index 0000000..37bf104
--- /dev/null
@@ -0,0 +1,31 @@
+package example.symphony;\r
+\r
+import java.util.Iterator;\r
+import peersim.core.Network;\r
+import peersim.core.Node;\r
+\r
+/**\r
+ * Adapter Class absolutely UNSAFE, just to be able to iterate peersim.core.Network\r
+ *\r
+ * @author Andrea Esposito <and1989@gmail.com>\r
+ */\r
+public class AdapterIterableNetwork implements Iterable<Node>, Iterator<Node> {\r
+\r
+    private int i = 0;\r
+\r
+    public Iterator<Node> iterator() {\r
+        return this;\r
+    }\r
+\r
+    public boolean hasNext() {\r
+        return i < Network.size();\r
+    }\r
+\r
+    public Node next() {\r
+        return Network.get(i++);\r
+    }\r
+\r
+    public void remove() {\r
+        throw new UnsupportedOperationException("Not supported yet.");\r
+    }\r
+}\r
diff --git a/contrib/psg/src/example/symphony/AdapterSymphonyNodeComparator.java b/contrib/psg/src/example/symphony/AdapterSymphonyNodeComparator.java
new file mode 100644 (file)
index 0000000..b05bbb6
--- /dev/null
@@ -0,0 +1,28 @@
+package example.symphony;\r
+\r
+import java.util.Comparator;\r
+\r
+import example.symphony.SymphonyProtocol.BootstrapStatus;\r
+import peersim.core.Node;\r
+\r
+/**\r
+ * Object-Adapter\r
+ *\r
+ * @author Andrea Esposito <and1989@gmail.com>\r
+ */\r
+public class AdapterSymphonyNodeComparator implements Comparator<Tuple<Node, BootstrapStatus>> {\r
+\r
+    private SymphonyNodeComparator comparator;\r
+\r
+    public AdapterSymphonyNodeComparator(SymphonyNodeComparator comparator) {\r
+        this.comparator = comparator;\r
+    }\r
+\r
+    public int compare(Tuple<Node, BootstrapStatus> o1, Tuple<Node, BootstrapStatus> o2) {\r
+\r
+        Node node1 = o1.x;\r
+        Node node2 = o2.x;\r
+\r
+        return comparator.compare(node1, node2);\r
+    }\r
+}\r
diff --git a/contrib/psg/src/example/symphony/Handler.java b/contrib/psg/src/example/symphony/Handler.java
new file mode 100644 (file)
index 0000000..c78d774
--- /dev/null
@@ -0,0 +1,19 @@
+package example.symphony;\r
+\r
+import peersim.core.Node;\r
+\r
+/**\r
+ *\r
+ * @author Andrea Esposito <and1989@gmail.com>\r
+ */\r
+public interface Handler {\r
+\r
+    /**\r
+     * Handler associable to a routing request\r
+     *\r
+     * @param src Symphony Protocol that has sent the routing request\r
+     * @param evt Tuple that contains: Node that manages the identifier, Identifier that the routing\r
+     * has done on\r
+     */\r
+    void handle(SymphonyProtocol src, Tuple<Node, Double> evt);\r
+}\r
diff --git a/contrib/psg/src/example/symphony/LeaveTest.java b/contrib/psg/src/example/symphony/LeaveTest.java
new file mode 100644 (file)
index 0000000..b4c9167
--- /dev/null
@@ -0,0 +1,77 @@
+package example.symphony;\r
+\r
+import peersim.config.Configuration;\r
+import peersim.core.CommonState;\r
+import peersim.core.Control;\r
+import peersim.core.Network;\r
+import peersim.core.Node;\r
+\r
+/**\r
+ *\r
+ * @author Andrea Esposito <and1989@gmail.com>\r
+ */\r
+public class LeaveTest implements Control {\r
+\r
+    private static final String PAR_NETMANAGER = "symphonynetworkmanager";\r
+    private static final String PAR_NUMBER_LEAVES = "n";\r
+    private static final String PAR_MIN_SIZE = "minsizeOnline";\r
+    private static final String PAR_WAIT_TARGET_SIZE = "waitTargetSizeToStart";\r
+    private final int networkManagerID;\r
+    private final double n;\r
+    private final int minSizeNetwork;\r
+    private int targetSize;\r
+\r
+    public LeaveTest(String prefix) {\r
+        networkManagerID = Configuration.getPid(prefix + "." + PAR_NETMANAGER);\r
+        double nAppo = Configuration.getDouble(prefix + "." + PAR_NUMBER_LEAVES);\r
+        if (!(nAppo > 0.0 && nAppo < 1.0)) {\r
+            n = (int) Math.round(nAppo);\r
+        } else {\r
+            n = nAppo;\r
+        }\r
+\r
+        minSizeNetwork = Configuration.getInt(prefix + "." + PAR_MIN_SIZE, -1);\r
+        targetSize = Configuration.getInt(prefix + "." + PAR_WAIT_TARGET_SIZE, -1);\r
+    }\r
+\r
+    public boolean execute() {\r
+\r
+        if (minSizeNetwork > 0) {\r
+\r
+            int onlineNode = 0;\r
+            AdapterIterableNetwork it = new AdapterIterableNetwork();\r
+            for (Node node : it) {\r
+                if (node.isUp()) {\r
+                    onlineNode++;\r
+                }\r
+            }\r
+\r
+            if (targetSize <= 0 || targetSize <= onlineNode) {\r
+                targetSize = -1;\r
+\r
+                // verify if i have to remove an exact number of nodes or a percentage of them\r
+                int actualN = (int) (n < 1.0 ? Math.ceil(Network.size() * n) : n);\r
+\r
+                for (int i = 0; i < actualN && Network.size() > 0; i++) {\r
+                    if (onlineNode > minSizeNetwork) {\r
+                        Node leaveNode = Network.get(Math.abs(CommonState.r.nextInt()) % Network.size());\r
+\r
+                        while (!leaveNode.isUp()) {\r
+                            leaveNode = Network.get(Math.abs(CommonState.r.nextInt()) % Network.size());\r
+                        }\r
+\r
+                        SymphonyNetworkManager networkManager = (SymphonyNetworkManager) leaveNode.getProtocol(networkManagerID);\r
+\r
+                        networkManager.leave(leaveNode);\r
+\r
+                        onlineNode--;\r
+                    } else {\r
+                        break;\r
+                    }\r
+                }\r
+            }\r
+        }\r
+\r
+        return false;\r
+    }\r
+}\r
diff --git a/contrib/psg/src/example/symphony/Message.java b/contrib/psg/src/example/symphony/Message.java
new file mode 100644 (file)
index 0000000..5f63d11
--- /dev/null
@@ -0,0 +1,90 @@
+package example.symphony;\r
+\r
+import peersim.core.Node;\r
+\r
+/**\r
+ *\r
+ * @author Andrea Esposito <and1989@gmail.com>\r
+ */\r
+public class Message implements Cloneable {\r
+\r
+    public enum MessageType {\r
+\r
+        ROUTE, ROUTE_RESPONSE, ROUTE_FAIL,\r
+        JOIN, JOIN_RESPONSE,\r
+        UPDATE_NEIGHBOURS, UPDATE_NEIGHBOURS_RESPONSE,\r
+        REQUEST_LONG_RANGE_LINK, ACCEPTED_LONG_RANGE_LINK, REJECT_LONG_RANGE_LINK, DISCONNECT_LONG_RANGE_LINK, UNAVAILABLE_LONG_RANGE_LINK,\r
+        UPDATE_STATUS, UPDATE_STATUS_RESPONSE,\r
+        LEAVE,\r
+        KEEP_ALIVE, KEEP_ALIVE_RESPONSE\r
+    }\r
+    private long hopCounter;\r
+    private MessageType type;\r
+    private Node src;\r
+    private Node currentHop;\r
+    private Object body;\r
+    private static long globalID = 0;\r
+    private final long id;\r
+\r
+    public Message(Object body, Node src, MessageType type) {\r
+        this.type = type;\r
+        this.src = src;\r
+        this.body = body;\r
+        hopCounter = 0;\r
+        id = globalID++;\r
+        currentHop = src;\r
+    }\r
+\r
+    public long getID() {\r
+        return id;\r
+    }\r
+\r
+    public Object getBody() {\r
+        return body;\r
+    }\r
+\r
+    public void incrementHop() {\r
+        hopCounter++;\r
+    }\r
+\r
+    public long getHop() {\r
+        return hopCounter;\r
+    }\r
+\r
+    public MessageType getType() {\r
+        return type;\r
+    }\r
+\r
+    public Node getSourceNode() {\r
+        return src;\r
+    }\r
+\r
+    public Node getCurrentHop() {\r
+        return currentHop;\r
+    }\r
+\r
+    public void setCurrentHop(Node currentHop) {\r
+        this.currentHop = currentHop;\r
+    }\r
+\r
+    @Override\r
+    public Object clone() throws CloneNotSupportedException {\r
+        return super.clone();\r
+    }\r
+\r
+    @Override\r
+    public String toString() {\r
+\r
+        StringBuilder builder = new StringBuilder();\r
+        builder.append("Message@").append(this.hashCode()).append("[\n");\r
+\r
+        builder.append("\tID : ").append(id).append(",\n");\r
+        builder.append("\tSource ID: ").append(src.getID()).append(",\n");\r
+        builder.append("\tType : ").append(type).append(",\n");\r
+        builder.append("\tBody : ").append(body).append(",\n");\r
+        builder.append("\tCurrent Hop ID: ").append(currentHop.getID()).append(",\n");\r
+        builder.append("\tHop Counter : ").append(hopCounter).append("\n]\n");\r
+\r
+        return builder.toString();\r
+    }\r
+}\r
diff --git a/contrib/psg/src/example/symphony/NetworkSizeEstimatorProtocolInterface.java b/contrib/psg/src/example/symphony/NetworkSizeEstimatorProtocolInterface.java
new file mode 100644 (file)
index 0000000..ffb8ba9
--- /dev/null
@@ -0,0 +1,13 @@
+package example.symphony;\r
+\r
+import peersim.core.Node;\r
+import peersim.core.Protocol;\r
+\r
+/**\r
+ *\r
+ * @author Andrea Esposito <and1989@gmail.com>\r
+ */\r
+public interface NetworkSizeEstimatorProtocolInterface extends Protocol {\r
+\r
+    public int getNetworkSize(Node node);\r
+}\r
diff --git a/contrib/psg/src/example/symphony/RandomRouteTest.java b/contrib/psg/src/example/symphony/RandomRouteTest.java
new file mode 100644 (file)
index 0000000..fe55f33
--- /dev/null
@@ -0,0 +1,48 @@
+package example.symphony;\r
+\r
+import java.util.logging.Level;\r
+import java.util.logging.Logger;\r
+import peersim.config.Configuration;\r
+import peersim.core.CommonState;\r
+import peersim.core.Control;\r
+import peersim.core.Network;\r
+import peersim.core.Node;\r
+\r
+/**\r
+ *\r
+ * @author Andrea Esposito <and1989@gmail.com>\r
+ */\r
+public class RandomRouteTest implements Control, Handler {\r
+\r
+    private static final String PAR_SYMPHONY = "symphony";\r
+    private final int symphonyID;\r
+\r
+    public RandomRouteTest(String prefix) {\r
+        symphonyID = Configuration.getPid(prefix + "." + PAR_SYMPHONY);\r
+    }\r
+\r
+    public boolean execute() {\r
+\r
+        Node src = Network.get(Math.abs(CommonState.r.nextInt()) % Network.size());\r
+\r
+        SymphonyProtocol symphony = (SymphonyProtocol) src.getProtocol(symphonyID);\r
+        try {\r
+            symphony.route(src, CommonState.r.nextDouble(), this);\r
+        } catch (RoutingException ex) {\r
+            Logger.getLogger(RandomRouteTest.class.getName()).log(Level.SEVERE, ex.getMessage());\r
+        }\r
+\r
+        return false;\r
+\r
+    }\r
+\r
+    public void handle(SymphonyProtocol symphony, Tuple<Node, Double> tuple) {\r
+\r
+        if (tuple == null) {\r
+            Logger.getLogger(RandomRouteTest.class.getName()).log(Level.SEVERE, "FAIL ROUTE RANDOMTEST");\r
+            return;\r
+        }\r
+\r
+        Logger.getLogger(RandomRouteTest.class.getName()).log(Level.FINE, symphony.getIdentifier() + " source find the manager of " + tuple.y + " and it is " + ((SymphonyProtocol) tuple.x.getProtocol(symphonyID)).getIdentifier());\r
+    }\r
+}\r
diff --git a/contrib/psg/src/example/symphony/RingRouteTest.java b/contrib/psg/src/example/symphony/RingRouteTest.java
new file mode 100644 (file)
index 0000000..06262cb
--- /dev/null
@@ -0,0 +1,150 @@
+package example.symphony;\r
+\r
+import java.util.Collection;\r
+import java.util.Collections;\r
+import java.util.HashSet;\r
+import java.util.LinkedList;\r
+import java.util.logging.Level;\r
+import java.util.logging.Logger;\r
+\r
+import example.symphony.SymphonyProtocol.BootstrapStatus;\r
+import peersim.config.Configuration;\r
+import peersim.core.Control;\r
+import peersim.core.Network;\r
+import peersim.core.Node;\r
+\r
+/**\r
+ *\r
+ * @author Andrea Esposito <and1989@gmail.com>\r
+ */\r
+public class RingRouteTest implements Control, Handler {\r
+\r
+    private static final String PAR_SYMPHONY = "symphony";\r
+    private static final String PAR_STARTNODE = "startnode";\r
+    private final int symphonyID;\r
+    private final int indexStartNode;\r
+    private Node start;\r
+    private boolean finished;\r
+    private boolean flagTimeout;\r
+    private HashSet<Node> antiLoopSet;\r
+\r
+    public RingRouteTest(String prefix) {\r
+        symphonyID = Configuration.getPid(prefix + "." + PAR_SYMPHONY);\r
+        indexStartNode = Configuration.getInt(prefix + "." + PAR_STARTNODE, 0);\r
+\r
+        finished = true;\r
+        flagTimeout = false;\r
+        antiLoopSet = new HashSet<Node>();\r
+    }\r
+\r
+    public boolean execute() {\r
+\r
+        if (!finished && flagTimeout) {\r
+\r
+            Logger.getLogger(RingRouteTest.class.getName()).log(Level.WARNING, "Sent msg but no aswer. Timeout. Ring Route Test terminated for Timeout.");\r
+\r
+            finished = true;\r
+            flagTimeout = false;\r
+        }\r
+\r
+        if (finished) {\r
+\r
+            flagTimeout = true;\r
+            antiLoopSet.clear();\r
+\r
+            int indexRealStartNode = indexStartNode;\r
+            Node realStartNode = Network.get(indexStartNode);\r
+            SymphonyProtocol symphony = (SymphonyProtocol) realStartNode.getProtocol(symphonyID);\r
+\r
+            while (!symphony.isBootstrapped() || !realStartNode.isUp()) {\r
+                indexRealStartNode = (indexRealStartNode + 1) % Network.size();\r
+                realStartNode = Network.get(indexRealStartNode);\r
+                symphony = (SymphonyProtocol) realStartNode.getProtocol(symphonyID);\r
+\r
+                if (indexRealStartNode == indexStartNode) {\r
+                    Logger.getLogger(RingRouteTest.class.getName()).log(Level.WARNING, "No ONLINE nodes. The ring is vanished. Ring Route Terminated.");\r
+                    finished = true;\r
+                    flagTimeout = false;\r
+                    return false;\r
+                }\r
+            }\r
+\r
+            start = realStartNode;\r
+            finished = false;\r
+\r
+            Logger.getLogger(RingRouteTest.class.getName()).log(Level.INFO, "RingRoute started.");\r
+\r
+            doRoute(start, true);\r
+        }\r
+\r
+        return false;\r
+    }\r
+\r
+    public void handle(SymphonyProtocol symphony, Tuple<Node, Double> tuple) {\r
+\r
+        if (tuple == null) {\r
+            Logger.getLogger(RingRouteTest.class.getName()).log(Level.SEVERE, "FAIL RING ROUTING");\r
+            finished = true;\r
+            return;\r
+        }\r
+\r
+        Logger.getLogger(RingRouteTest.class.getName()).log(Level.FINER, symphony.getIdentifier() + " source find the manager of " + tuple.y + " and it is " + ((SymphonyProtocol) tuple.x.getProtocol(symphonyID)).getIdentifier());\r
+\r
+        doRoute(tuple.x, false);\r
+    }\r
+\r
+    private void doRoute(Node node, boolean firstTime) {\r
+\r
+        SymphonyProtocol symphonyStartNode = (SymphonyProtocol) start.getProtocol(symphonyID);\r
+\r
+        if (!symphonyStartNode.isBootstrapped()) {\r
+            Logger.getLogger(RingRouteTest.class.getName()).log(Level.INFO, "The node i started from left. Ring Route Terminated.");\r
+            finished = true;\r
+            return;\r
+        }\r
+\r
+        if (!firstTime && node.equals(start)) {\r
+            Logger.getLogger(RingRouteTest.class.getName()).log(Level.INFO, "RingRoute Terminated");\r
+            finished = true;\r
+            return;\r
+        }\r
+\r
+        if (antiLoopSet.contains(node)) {\r
+            Logger.getLogger(RingRouteTest.class.getName()).log(Level.INFO, "Not able to reach the node that i started from. Ring Route Terminated.");\r
+            finished = true;\r
+            return;\r
+        } else {\r
+            antiLoopSet.add(node);\r
+        }\r
+\r
+        SymphonyProtocol symphony = (SymphonyProtocol) node.getProtocol(symphonyID);\r
+        AdapterSymphonyNodeComparator adapterSymphonyNodeComparator = new AdapterSymphonyNodeComparator(new SymphonyNodeComparator(symphonyID, node));\r
+\r
+        Collection<Tuple<Node, BootstrapStatus>> collection = (Collection<Tuple<Node, BootstrapStatus>>) symphony.leftShortRangeLinks.clone();\r
+        LinkedList<Tuple<Node, BootstrapStatus>> list = new LinkedList<Tuple<Node, BootstrapStatus>>(collection);\r
+        Collections.sort(list, adapterSymphonyNodeComparator);\r
+\r
+        Node targetNode = null;\r
+        for (Tuple<Node, BootstrapStatus> tuple : list) {\r
+            if (tuple.y == BootstrapStatus.ONLINE) {\r
+                targetNode = tuple.x;\r
+                break;\r
+            }\r
+        }\r
+\r
+        if (targetNode == null || !targetNode.isUp()) {\r
+            Logger.getLogger(RingRouteTest.class.getName()).log(Level.WARNING, "Terminated Ring Route but not done completely");\r
+            finished = true;\r
+            return;\r
+        }\r
+\r
+        SymphonyProtocol symphonyTarget = (SymphonyProtocol) targetNode.getProtocol(symphonyID);\r
+        try {\r
+            symphony.route(node, symphonyTarget.getIdentifier(), this);\r
+            Logger.getLogger(RingRouteTest.class.getName()).log(Level.FINEST, "Ring from: " + symphony.getIdentifier() + " to " + symphonyTarget.getIdentifier());\r
+        } catch (RoutingException ex) {\r
+            Logger.getLogger(RingRouteTest.class.getName()).log(Level.WARNING, "Finito AnelloRoute MA NON FATTO TUTTO");\r
+            finished = true;\r
+        }\r
+    }\r
+}\r
diff --git a/contrib/psg/src/example/symphony/RoutingException.java b/contrib/psg/src/example/symphony/RoutingException.java
new file mode 100644 (file)
index 0000000..1b6bb9b
--- /dev/null
@@ -0,0 +1,15 @@
+package example.symphony;\r
+\r
+/**\r
+ *\r
+ * @author Andrea Esposito <and1989@gmail.com>\r
+ */\r
+public class RoutingException extends Exception {\r
+\r
+    public RoutingException() {\r
+    }\r
+\r
+    public RoutingException(String msg) {\r
+        super(msg);\r
+    }\r
+}\r
diff --git a/contrib/psg/src/example/symphony/SimpleNetworkSizeEstimatorProtocol.java b/contrib/psg/src/example/symphony/SimpleNetworkSizeEstimatorProtocol.java
new file mode 100644 (file)
index 0000000..6d17371
--- /dev/null
@@ -0,0 +1,23 @@
+package example.symphony;\r
+\r
+import peersim.core.Network;\r
+import peersim.core.Node;\r
+\r
+/**\r
+ *\r
+ * @author Andrea Esposito <and1989@gmail.com>\r
+ */\r
+public class SimpleNetworkSizeEstimatorProtocol implements NetworkSizeEstimatorProtocolInterface {\r
+\r
+    public SimpleNetworkSizeEstimatorProtocol(String prefix) {\r
+    }\r
+\r
+    public int getNetworkSize(Node node) {\r
+        return Network.size();\r
+    }\r
+\r
+    @Override\r
+    public Object clone() {\r
+        return this;\r
+    }\r
+}\r
diff --git a/contrib/psg/src/example/symphony/SymphonyEstimationProtocol.java b/contrib/psg/src/example/symphony/SymphonyEstimationProtocol.java
new file mode 100644 (file)
index 0000000..642677d
--- /dev/null
@@ -0,0 +1,106 @@
+package example.symphony;\r
+\r
+import java.util.*;\r
+import peersim.config.Configuration;\r
+import peersim.core.Network;\r
+import peersim.core.Node;\r
+\r
+/**\r
+ *\r
+ * @author Andrea Esposito <and1989@gmail.com>\r
+ */\r
+public class SymphonyEstimationProtocol implements NetworkSizeEstimatorProtocolInterface {\r
+\r
+    private static final String PAR_SYMPHONY = "symphony";\r
+    private static final String PAR_S = "s";\r
+    private final int symphonyID;\r
+    private final int s;\r
+\r
+    public SymphonyEstimationProtocol(String prefix) {\r
+        symphonyID = Configuration.getPid(prefix + "." + PAR_SYMPHONY);\r
+        s = Configuration.getInt(prefix + "." + PAR_S, -1);\r
+    }\r
+\r
+    /**\r
+     * Implementation of the estimated network size as a variant of the paper one. It use anyway the\r
+     * idea to calculate the size from the length segments but without exchanging the information\r
+     * with the neighbours instead using only the local information.\r
+     */\r
+    public int getNetworkSize(Node node) {\r
+        SymphonyProtocol symphony = (SymphonyProtocol) node.getProtocol(symphonyID);\r
+\r
+        // If the node is not yet inside the ring i return the minimum size (2 nodes)\r
+        if (!symphony.isBootstrapped()) {\r
+            return 2;\r
+        }\r
+\r
+        /*\r
+         * I clone the short range links views (wrapped into an ArrayList because the returned list\r
+         * 'Arrays.asList doesn't support the "removeAll" method or better its size is fixed)\r
+         */\r
+        ArrayList<Tuple<Node, SymphonyProtocol.BootstrapStatus>> leftList = new ArrayList<Tuple<Node, SymphonyProtocol.BootstrapStatus>>(Arrays.asList((Tuple<Node, SymphonyProtocol.BootstrapStatus>[]) symphony.leftShortRangeLinks.toArray(new Tuple[0])));\r
+        ArrayList<Tuple<Node, SymphonyProtocol.BootstrapStatus>> rightList = new ArrayList<Tuple<Node, SymphonyProtocol.BootstrapStatus>>(Arrays.asList((Tuple<Node, SymphonyProtocol.BootstrapStatus>[]) symphony.rightShortRangeLinks.toArray(new Tuple[0])));\r
+\r
+        // Remove the neighbours that are offline\r
+        LinkedList<Tuple<Node, SymphonyProtocol.BootstrapStatus>> offlineNeighbors = new LinkedList<Tuple<Node, SymphonyProtocol.BootstrapStatus>>();\r
+        for (Tuple<Node, SymphonyProtocol.BootstrapStatus> tuple : leftList) {\r
+            if (tuple.y == SymphonyProtocol.BootstrapStatus.OFFLINE) {\r
+                offlineNeighbors.add(tuple);\r
+            }\r
+        }\r
+        leftList.removeAll(offlineNeighbors);\r
+        offlineNeighbors.clear();\r
+        for (Tuple<Node, SymphonyProtocol.BootstrapStatus> tuple : rightList) {\r
+            if (tuple.y == SymphonyProtocol.BootstrapStatus.OFFLINE) {\r
+                offlineNeighbors.add(tuple);\r
+            }\r
+        }\r
+        rightList.removeAll(offlineNeighbors);\r
+\r
+        // Sort the neighbours based on the distance from me\r
+        Comparator<Tuple<Node, SymphonyProtocol.BootstrapStatus>> comparator = new AdapterSymphonyNodeComparator(new SymphonyNodeComparator(symphonyID, symphony.getIdentifier()));\r
+        Collections.sort(leftList, comparator);\r
+        Collections.sort(rightList, comparator);\r
+\r
+        // Calculate the variables to estimated the network size\r
+        double Xs = 0;\r
+        int countS = 0;\r
+\r
+        List<Tuple<Node, SymphonyProtocol.BootstrapStatus>> appoList[] = new List[2];\r
+        appoList[0] = leftList;\r
+        appoList[1] = rightList;\r
+\r
+        double[] appoPrecIdentifier = new double[]{symphony.getIdentifier(), symphony.getIdentifier()};\r
+        int[] appoCurrentIndex = new int[]{0, 0};\r
+\r
+        int realS = (int) (s <= 0 ? Math.log(Network.size() / Math.log(2)) : s);\r
+\r
+        for (int i = 0; i < realS; i++) {\r
+            double precIdentifier = appoPrecIdentifier[i % 2];\r
+            int currentIndex = appoCurrentIndex[i % 2];\r
+            List<Tuple<Node, SymphonyProtocol.BootstrapStatus>> currentList = appoList[i % 2];\r
+\r
+            try {\r
+                double currentIdentifier = ((SymphonyProtocol) currentList.get(currentIndex).x.getProtocol(symphonyID)).getIdentifier();\r
+\r
+                appoPrecIdentifier[i % 2] = currentIdentifier;\r
+                appoCurrentIndex[i % 2] = appoCurrentIndex[i % 2] + 1;\r
+\r
+                double distance = Math.abs(currentIdentifier - precIdentifier);\r
+                Xs += Math.min(distance, 1.0 - distance);\r
+                countS++;\r
+            } catch (IndexOutOfBoundsException ex) {\r
+                // Simply i skip the counting\r
+            }\r
+        }\r
+\r
+        int ret = Xs == 0 ? 0 : (int) Math.round(countS / Xs);\r
+\r
+        return ret;\r
+    }\r
+\r
+    @Override\r
+    public Object clone() {\r
+        return this;\r
+    }\r
+}\r
diff --git a/contrib/psg/src/example/symphony/SymphonyNetworkBuilder.java b/contrib/psg/src/example/symphony/SymphonyNetworkBuilder.java
new file mode 100644 (file)
index 0000000..a012d60
--- /dev/null
@@ -0,0 +1,157 @@
+package example.symphony;\r
+\r
+import java.util.Collection;\r
+import java.util.Comparator;\r
+import java.util.LinkedList;\r
+import java.util.logging.Level;\r
+import java.util.logging.Logger;\r
+\r
+import example.symphony.SymphonyProtocol.BootstrapStatus;\r
+import peersim.config.Configuration;\r
+import peersim.core.CommonState;\r
+import peersim.core.Control;\r
+import peersim.core.Network;\r
+import peersim.core.Node;\r
+\r
+/**\r
+ * Inizializer that create the initial ring\r
+ *\r
+ * @author Andrea Esposito <and1989@gmail.com>\r
+ */\r
+public class SymphonyNetworkBuilder implements Control {\r
+\r
+    private static final String PAR_SYMHONY = "symphony";\r
+    private static final String PAR_LONG_LINK = "createLongLinks";\r
+    private static final String PAR_MAX_ATTEMPTS = "attempts";\r
+    private final int symphonyID;\r
+    private final boolean createLongRangeLinks;\r
+    private final int MAX_ATTEMPTS;\r
+\r
+    public SymphonyNetworkBuilder(String prefix) {\r
+\r
+        symphonyID = Configuration.getPid(prefix + "." + PAR_SYMHONY);\r
+        createLongRangeLinks = Configuration.getBoolean(prefix + "." + PAR_LONG_LINK, true);\r
+        MAX_ATTEMPTS = Configuration.getInt(prefix + "." + PAR_MAX_ATTEMPTS, 5);\r
+    }\r
+\r
+    public boolean execute() {\r
+\r
+        // Sort the network for convenience (from 0.0 to 1.0)\r
+        Network.sort(new Comparator<Node>() {\r
+\r
+            public int compare(Node o1, Node o2) {\r
+\r
+                SymphonyProtocol symphony1 = (SymphonyProtocol) o1.getProtocol(symphonyID);\r
+                SymphonyProtocol symphony2 = (SymphonyProtocol) o2.getProtocol(symphonyID);\r
+\r
+                Double identifier1 = symphony1.getIdentifier();\r
+                Double identifier2 = symphony2.getIdentifier();\r
+\r
+                return identifier1.compareTo(identifier2);\r
+            }\r
+        });\r
+\r
+        int numShortLinksPerSide = ((SymphonyProtocol) Network.get(0).getProtocol(symphonyID)).numberShortRangeLinksPerSide;\r
+\r
+        for (int i = 0; i < Network.size(); i++) {\r
+\r
+            Node node = Network.get(i);\r
+            SymphonyProtocol symphonyNode = (SymphonyProtocol) node.getProtocol(symphonyID);\r
+\r
+            // Create the short links\r
+            for (int j = 1; j <= numShortLinksPerSide; j++) {\r
+\r
+                int pos = i - j;\r
+                pos = pos < 0 ? Network.size() + pos : pos;\r
+                symphonyNode.rightShortRangeLinks.add(new Tuple<Node, BootstrapStatus>(Network.get(pos), BootstrapStatus.ONLINE));\r
+\r
+                pos = (i + j) % Network.size();\r
+                symphonyNode.leftShortRangeLinks.add(new Tuple<Node, BootstrapStatus>(Network.get(pos), BootstrapStatus.ONLINE));\r
+            }\r
+\r
+            symphonyNode.loggedIntoNetwork = SymphonyProtocol.BootstrapStatus.ONLINE;\r
+        }\r
+\r
+        /*\r
+         * UPDATE: Putted a flag to decide if perform this part of code or not at configuration\r
+         * time. At default i create the long range links.\r
+         *\r
+         * The Long Range Links could be left to the networkmanager but the tests that we'll do have\r
+         * to put into account that in an initial phase will be some message exchanging to create\r
+         * the long range links and so the latency is faked... for that reason the long range links\r
+         * are created manually here such a way to have a complete symphony network from the\r
+         * beginning.\r
+         */\r
+        if (createLongRangeLinks) {\r
+            for (Node node : new AdapterIterableNetwork()) {\r
+\r
+                SymphonyProtocol symphonyNode = (SymphonyProtocol) node.getProtocol(symphonyID);\r
+\r
+                // Create the long links\r
+                int k = (int) Math.ceil(Math.log(Network.size()) / Math.log(2));\r
+\r
+                if (symphonyNode.fixedLongRangeLinks) {\r
+                    k = symphonyNode.numberFixedLongRangeLinks;\r
+                }\r
+\r
+                Collection<Node> allShortLinks = new LinkedList<Node>();\r
+                for (Tuple<Node, BootstrapStatus> shortTuple : symphonyNode.leftShortRangeLinks) {\r
+                    allShortLinks.add(shortTuple.x);\r
+                }\r
+                for (Tuple<Node, BootstrapStatus> shortTuple : symphonyNode.rightShortRangeLinks) {\r
+                    allShortLinks.add(shortTuple.x);\r
+                }\r
+\r
+                int j = 0;\r
+                int attempts = MAX_ATTEMPTS;\r
+                while (j <= k) {\r
+\r
+                    double distance = Math.exp(k * (CommonState.r.nextDouble() - 1.0));\r
+                    double targetIdentifier = (symphonyNode.getIdentifier() + distance) % 1;\r
+\r
+                    Node targetNode;\r
+                    try {\r
+\r
+                        // use the unidirectional routing because i want to catch the manager\r
+                        targetNode = symphonyNode.findClosestNode(targetIdentifier, new AdapterIterableNetwork(), true);\r
+                        SymphonyProtocol symphonyTargetNode = (SymphonyProtocol) targetNode.getProtocol(symphonyID);\r
+                        if (!targetNode.equals(node)\r
+                                && !symphonyNode.longRangeLinksOutgoing.contains(targetNode)\r
+                                && symphonyTargetNode.longRangeLinksIncoming.size() < (2 * k)\r
+                                && !allShortLinks.contains(targetNode)) {\r
+\r
+                            boolean fresh = symphonyTargetNode.longRangeLinksIncoming.add(node);\r
+\r
+                            if (fresh) {\r
+                                j++;\r
+                                attempts = MAX_ATTEMPTS;\r
+                                symphonyNode.longRangeLinksOutgoing.add(targetNode);\r
+                            } else {\r
+                                attempts--;\r
+                                if (attempts <= 0) { // Because i don't want to loop i try a finite number of times\r
+                                    attempts = MAX_ATTEMPTS;\r
+                                    j++;\r
+                                }\r
+\r
+                            }\r
+                        } else {\r
+                            attempts--;\r
+                            if (attempts <= 0) { // Because i don't want to loop i try a finite number of times\r
+                                attempts = MAX_ATTEMPTS;\r
+                                j++;\r
+                            }\r
+\r
+                        }\r
+                    } catch (RoutingException ex) {\r
+                        Logger.getLogger(SymphonyNetworkBuilder.class.getName()).log(Level.SEVERE, null, ex);\r
+                    }\r
+                }\r
+            }\r
+        }\r
+\r
+        // Shuffle\r
+        Network.shuffle();\r
+\r
+        return false;\r
+    }\r
+}\r
diff --git a/contrib/psg/src/example/symphony/SymphonyNetworkChecker.java b/contrib/psg/src/example/symphony/SymphonyNetworkChecker.java
new file mode 100644 (file)
index 0000000..d5f2aef
--- /dev/null
@@ -0,0 +1,123 @@
+package example.symphony;\r
+\r
+import java.util.Collections;\r
+import java.util.HashSet;\r
+import java.util.Set;\r
+import java.util.logging.Level;\r
+import java.util.logging.Logger;\r
+\r
+import example.symphony.SymphonyProtocol.BootstrapStatus;\r
+import peersim.config.Configuration;\r
+import peersim.core.Control;\r
+import peersim.core.Network;\r
+import peersim.core.Node;\r
+\r
+/**\r
+ *\r
+ * @author Andrea Esposito <and1989@gmail.com>\r
+ */\r
+public class SymphonyNetworkChecker implements Control {\r
+\r
+    private static final String PAR_SYMHONY = "symphony";\r
+    private static final String PAR_NETSIZE = "networkestimator";\r
+    private final int symphonyID;\r
+    private final int networkEstimatorID;\r
+\r
+    public SymphonyNetworkChecker(String prefix) {\r
+        symphonyID = Configuration.getPid(prefix + "." + PAR_SYMHONY);\r
+        networkEstimatorID = Configuration.getPid(prefix + "." + PAR_NETSIZE);\r
+    }\r
+\r
+    public boolean execute() {\r
+\r
+        boolean isNotOK = false;\r
+\r
+        Set<Double> idSet = new HashSet<Double>();\r
+        Iterable<Node> coll = new AdapterIterableNetwork();\r
+\r
+        int countOnline = 0;\r
+        int count = 0;\r
+        int notBootstrapped = 0;\r
+        int countKO = 0;\r
+        int disconnected = 0;\r
+\r
+        for (Node node : coll) {\r
+            SymphonyProtocol symphony = (SymphonyProtocol) node.getProtocol(symphonyID);\r
+\r
+            if (!node.isUp()) {\r
+                disconnected++;\r
+            } else {\r
+                count++;\r
+            }\r
+\r
+            if (symphony.loggedIntoNetwork == SymphonyProtocol.BootstrapStatus.ONLINE) {\r
+\r
+                countOnline++;\r
+\r
+                NetworkSizeEstimatorProtocolInterface networkEstimator = (NetworkSizeEstimatorProtocolInterface) node.getProtocol(networkEstimatorID);\r
+                int k = (int) Math.ceil(Math.log(networkEstimator.getNetworkSize(node)) / Math.log(2));\r
+\r
+                boolean checkLeftShortRangeLinks = symphony.leftShortRangeLinks.size() > 0 && symphony.leftShortRangeLinks.size() <= symphony.numberShortRangeLinksPerSide;\r
+                boolean checkRightShortRangeLinks = symphony.rightShortRangeLinks.size() > 0 && symphony.rightShortRangeLinks.size() <= symphony.numberShortRangeLinksPerSide;\r
+\r
+                boolean oneNeighborOnline = false;\r
+                for (Tuple<Node, BootstrapStatus> leftTuple : symphony.leftShortRangeLinks) {\r
+                    if (leftTuple.y != BootstrapStatus.ONLINE && leftTuple.y != BootstrapStatus.OFFLINE) {\r
+                        notBootstrapped++;\r
+                    } else {\r
+                        oneNeighborOnline = true;\r
+                        checkLeftShortRangeLinks = checkLeftShortRangeLinks && SymphonyProtocol.isLeftNeighbour(node, leftTuple.x);\r
+                    }\r
+                }\r
+                checkLeftShortRangeLinks = checkLeftShortRangeLinks && oneNeighborOnline;\r
+\r
+                oneNeighborOnline = false;\r
+                for (Tuple<Node, BootstrapStatus> rightTuple : symphony.rightShortRangeLinks) {\r
+                    if (rightTuple.y != BootstrapStatus.ONLINE && rightTuple.y != BootstrapStatus.OFFLINE) {\r
+                        notBootstrapped++;\r
+                    } else {\r
+                        oneNeighborOnline = true;\r
+                        checkRightShortRangeLinks = checkRightShortRangeLinks && !SymphonyProtocol.isLeftNeighbour(node, rightTuple.x);\r
+                    }\r
+                }\r
+                checkRightShortRangeLinks = checkRightShortRangeLinks && oneNeighborOnline;\r
+\r
+                // Check if the node is in its neighbours\r
+                if (checkLeftShortRangeLinks) {\r
+                    AdapterSymphonyNodeComparator comparator = new AdapterSymphonyNodeComparator(new SymphonyNodeComparator(symphonyID, node));\r
+                    checkLeftShortRangeLinks = checkLeftShortRangeLinks && !Collections.min(symphony.leftShortRangeLinks, comparator).x.equals(node);\r
+                }\r
+\r
+                if (checkRightShortRangeLinks) {\r
+                    AdapterSymphonyNodeComparator comparator = new AdapterSymphonyNodeComparator(new SymphonyNodeComparator(symphonyID, node));\r
+                    checkRightShortRangeLinks = checkRightShortRangeLinks && !Collections.min(symphony.rightShortRangeLinks, comparator).x.equals(node);\r
+                }\r
+\r
+                boolean checkLongRangeLinksOutgoing = !symphony.longRangeLinksOutgoing.contains(node);\r
+                boolean checkLongRangeLinksIncoming = /*\r
+                         * symphony.longRangeLinksIncoming.size() <= (2 * k) &&\r
+                         */ !symphony.longRangeLinksIncoming.contains(node);\r
+\r
+                boolean checkUniqueID = !idSet.contains(symphony.getIdentifier());\r
+                idSet.add(symphony.getIdentifier());\r
+\r
+                boolean nextIsNotOK = !(checkUniqueID && checkLeftShortRangeLinks && checkRightShortRangeLinks && checkLongRangeLinksOutgoing && checkLongRangeLinksIncoming);\r
+\r
+                if (nextIsNotOK) {\r
+                    countKO++;\r
+                    Logger.getLogger(SymphonyNetworkChecker.class.getName()).log(Level.SEVERE, "OPS");\r
+                }\r
+\r
+                isNotOK = isNotOK || nextIsNotOK;\r
+            }\r
+        }\r
+\r
+        System.out.println("Error: " + countKO);\r
+        System.out.println("Online: " + countOnline + "/" + count);\r
+        System.out.println("Not Bootstrapped: " + notBootstrapped);\r
+        System.out.println("Disconnected: " + disconnected);\r
+        System.out.println("Network Size: " + Network.size());\r
+\r
+        return isNotOK;\r
+    }\r
+}\r
diff --git a/contrib/psg/src/example/symphony/SymphonyNetworkManager.java b/contrib/psg/src/example/symphony/SymphonyNetworkManager.java
new file mode 100644 (file)
index 0000000..4a1277f
--- /dev/null
@@ -0,0 +1,864 @@
+package example.symphony;\r
+\r
+import java.util.*;\r
+import java.util.logging.Level;\r
+import java.util.logging.Logger;\r
+\r
+import example.symphony.Message.MessageType;\r
+import example.symphony.SymphonyProtocol.BootstrapStatus;\r
+import peersim.cdsim.CDProtocol;\r
+import peersim.config.Configuration;\r
+import peersim.core.CommonState;\r
+import peersim.core.Fallible;\r
+import peersim.core.Node;\r
+import peersim.edsim.EDProtocol;\r
+import peersim.transport.Transport;\r
+\r
+/**\r
+ *\r
+ * @author Andrea Esposito <and1989@gmail.com>\r
+ */\r
+public class SymphonyNetworkManager implements EDProtocol, CDProtocol {\r
+\r
+    private static final String PAR_SYMPHONY = "symphony";\r
+    private static final String PAR_TRANSP = "transport";\r
+    private static final String PAR_ATTEMPTS = "attempts";\r
+    private static final String PAR_NETSIZE = "networkestimator";\r
+    private static final String PAR_NUM_TIMEOUT = "nTimeout";\r
+    private static final String PAR_RELINKING = "relinking";\r
+    private static final String PAR_RELINKING_LOWER_BOUND = "relinkingLowerBound";\r
+    private static final String PAR_RELINKING_UPPER_BOUND = "relinkingUpperBound";\r
+    private static final int DEFAULT_K = 1;\r
+    private static final int DEFAULT_N = 2;\r
+    private static final double DEFAULT_RELINKING_LOWER_BOUND = 0.5;\r
+    private static final double DEFAULT_RELINKING_UPPER_BOUND = 2.0;\r
+    private final String prefix;\r
+    private final int symphonyID;\r
+    private final int transportID;\r
+    private final int networkEstimatorID;\r
+    private final int attempts;\r
+    private final int pid;\r
+    private final int nTimeout;\r
+    private final HashMap<Node, Integer> keepAliveMap;\r
+    private final boolean relinkingProtocolActivated;\r
+    private final double relinkingUpperBound;\r
+    private final double relinkingLowerBound;\r
+    private int k = DEFAULT_K; // Number of Long Range Link\r
+    private int n = DEFAULT_N; // Estimation Network size\r
+    private static boolean firstPrintConfig = true;\r
+    /*\r
+     * Estimation Network size at which last long distance link was established, at the beginning -1\r
+     * to indicate that we never had Long Range Links\r
+     */\r
+    private int nLink = -1;\r
+    private int currentAttempts;\r
+\r
+    public SymphonyNetworkManager(String prefix) {\r
+\r
+        this.prefix = prefix;\r
+        pid = Configuration.lookupPid(prefix.replaceAll("protocol.", ""));\r
+        symphonyID = Configuration.getPid(prefix + "." + PAR_SYMPHONY);\r
+        transportID = Configuration.getPid(prefix + "." + PAR_TRANSP);\r
+        networkEstimatorID = Configuration.getPid(prefix + "." + PAR_NETSIZE);\r
+        attempts = Configuration.getInt(prefix + "." + PAR_ATTEMPTS);\r
+        nTimeout = Configuration.getInt(prefix + "." + PAR_NUM_TIMEOUT, 10);\r
+        relinkingProtocolActivated = !Configuration.getString(prefix + "." + PAR_RELINKING, "on").toLowerCase().equals("off");\r
+        double relinkingLowerBoundAppo = Configuration.getDouble(prefix + "." + PAR_RELINKING_LOWER_BOUND, DEFAULT_RELINKING_LOWER_BOUND);\r
+        double relinkingUpperBoundAppo = Configuration.getDouble(prefix + "." + PAR_RELINKING_UPPER_BOUND, DEFAULT_RELINKING_UPPER_BOUND);\r
+        if (relinkingLowerBoundAppo > relinkingUpperBoundAppo) {\r
+            relinkingLowerBound = DEFAULT_RELINKING_LOWER_BOUND;\r
+            relinkingUpperBound = DEFAULT_RELINKING_UPPER_BOUND;\r
+        } else {\r
+            relinkingLowerBound = relinkingLowerBoundAppo;\r
+            relinkingUpperBound = relinkingUpperBoundAppo;\r
+        }\r
+\r
+        keepAliveMap = new HashMap<Node, Integer>();\r
+\r
+        printConfig();\r
+    }\r
+\r
+    private void printConfig() {\r
+\r
+        if (firstPrintConfig) {\r
+            firstPrintConfig = false;\r
+            System.out.println(SymphonyNetworkManager.class.getSimpleName() + " Configuration:");\r
+            System.out.println("- Attempts per LongRangeLinks: " + attempts);\r
+            System.out.println("- Number of Timeout before a node is considered OFFLINE (through Keep-alive):" + nTimeout);\r
+            System.out.println("- Relinking: " + (relinkingProtocolActivated ? "ON" : "OFF"));\r
+            System.out.println("- Relinking Range: [" + relinkingLowerBound + ", " + relinkingUpperBound + "]");\r
+            System.out.println("-------------------------------\n");\r
+        }\r
+    }\r
+\r
+    public void join(final Node node, final Node bootstrapNode) throws RoutingException {\r
+        final SymphonyProtocol bootstrapSymphony = (SymphonyProtocol) bootstrapNode.getProtocol(symphonyID);\r
+        SymphonyProtocol symphony = (SymphonyProtocol) node.getProtocol(symphonyID);\r
+\r
+        /*\r
+         * Search (through the bootstrap node) and contact the Manager Node of myself such a way to\r
+         * be able to insert myself into the ring and create the short links\r
+         *\r
+         */\r
+        bootstrapSymphony.route(bootstrapNode, symphony.getIdentifier(), new Handler() {\r
+\r
+            public void handle(SymphonyProtocol src, Tuple<Node, Double> tuple) {\r
+                if (tuple == null) {\r
+                    Logger.getLogger(SymphonyNetworkManager.class.getName()).log(Level.SEVERE, "FAIL ROUTE JOIN");\r
+                    node.setFailState(Fallible.DEAD);\r
+                    return;\r
+                }\r
+\r
+                Node managerNode = tuple.x;\r
+\r
+                Transport transport = (Transport) node.getProtocol(transportID);\r
+                Message msg = new Message(node, node, MessageType.JOIN);\r
+                transport.send(node, managerNode, msg, pid);\r
+            }\r
+        });\r
+\r
+        // The Long Range Links are added after that i joined the ring (before i can't because i haven't got the nodes to do the routing)\r
+    }\r
+\r
+    /**\r
+     * Conservative Re-Linking (i reuse the ones already created: not all fresh)\r
+     *\r
+     * @param node\r
+     */\r
+    public void updateLongRangeLinks(Node node) {\r
+        SymphonyProtocol symphony = (SymphonyProtocol) node.getProtocol(symphonyID);\r
+        Transport transport = (Transport) node.getProtocol(transportID);\r
+\r
+        // if too much links i delete the farest ones\r
+        while (symphony.longRangeLinksOutgoing.size() > k) {\r
+            Node distantNode = Collections.max(symphony.longRangeLinksOutgoing, new SymphonyNodeComparator(symphonyID, node));\r
+            symphony.longRangeLinksOutgoing.remove(distantNode);\r
+\r
+            // Communicate to the outgoing node that it ins't anymore one of my long range links\r
+            Message disconnectMsg = new Message(null, node, MessageType.DISCONNECT_LONG_RANGE_LINK);\r
+            transport.send(node, distantNode, disconnectMsg, pid);\r
+        }\r
+\r
+        // I can search Long Range Links only if i'm into the ring and i'm able to do routing\r
+        if (symphony.isBootstrapped()) {\r
+            // if only few i try again, untill attempts times, to add new ones\r
+            int difference = k - symphony.longRangeLinksOutgoing.size();\r
+            currentAttempts = attempts;\r
+            for (int i = 0; i < difference; i++) {\r
+                sendLongRangeLinkRequest(symphony, node);\r
+            }\r
+        }\r
+    }\r
+    private static final int MAX_ANTILOOP_COUNT_MANAGER_MYSELF = 5;\r
+    private int antiLoopManagerMySelf = 0;\r
+\r
+    private void sendLongRangeLinkRequest(final SymphonyProtocol symphony, final Node node) {\r
+        boolean routingOk;\r
+        do {\r
+            double distance = Math.exp((Math.log(n) / Math.log(2)) * (CommonState.r.nextDouble() - 1.0)); // Harmonic Distribution\r
+            double targetIdentifier = (symphony.getIdentifier() + distance) % 1;\r
+            try {\r
+\r
+                symphony.route(node, targetIdentifier, new Handler() {\r
+\r
+                    public void handle(SymphonyProtocol src, Tuple<Node, Double> tuple) {\r
+\r
+                        if (tuple == null) {\r
+                            Logger.getLogger(SymphonyNetworkManager.class.getName()).log(Level.SEVERE, "FAIL ROUTE SENDLONGRANGELINKREQUEST");\r
+                            return;\r
+                        }\r
+\r
+                        Collection<Node> allShortLinks = new LinkedList<Node>();\r
+                        for (Tuple<Node, BootstrapStatus> shortTuple : symphony.leftShortRangeLinks) {\r
+                            allShortLinks.add(shortTuple.x);\r
+                        }\r
+                        for (Tuple<Node, BootstrapStatus> shortTuple : symphony.rightShortRangeLinks) {\r
+                            allShortLinks.add(shortTuple.x);\r
+                        }\r
+\r
+                        /*\r
+                         *\r
+                         * I'm myself one of my short links, special case... i try again without\r
+                         * reduce the attempts for a maximum of MAX_ANTILOOP_COUNT_MANAGER_MYSELF\r
+                         * times after that i start again to reduce the attempts\r
+                         */\r
+                        if (tuple.x.equals(node) || allShortLinks.contains(tuple.x)) {\r
+\r
+                            if (antiLoopManagerMySelf < MAX_ANTILOOP_COUNT_MANAGER_MYSELF) {\r
+\r
+                                antiLoopManagerMySelf++;\r
+                                sendLongRangeLinkRequest(symphony, node);\r
+                            } else {\r
+                                antiLoopManagerMySelf = 0;\r
+                                currentAttempts--;\r
+                            }\r
+                        } else {\r
+\r
+                            boolean alreadyAdded = symphony.longRangeLinksOutgoing.contains(tuple.x);\r
+                            /*\r
+                             *\r
+                             * OPINABLE: DESCREASE ATTEMPTS ONLY FOR REJECT? If yes i have to manage\r
+                             * the possible loop (nodi exhaurited so already all added)\r
+                             */\r
+                            if (alreadyAdded && currentAttempts > 0) {\r
+                                currentAttempts--;\r
+                                sendLongRangeLinkRequest(symphony, node);\r
+                            } else if (!alreadyAdded) {\r
+                                Message msg = new Message(null, node, MessageType.REQUEST_LONG_RANGE_LINK);\r
+                                Transport transport = (Transport) node.getProtocol(transportID);\r
+                                transport.send(node, tuple.x, msg, pid);\r
+                            }\r
+                        }\r
+                    }\r
+                });\r
+                routingOk = true;\r
+            } catch (RoutingException ex) {\r
+                routingOk = false;\r
+            }\r
+        } while (!routingOk);\r
+    }\r
+\r
+    public void leave(Node node) {\r
+        SymphonyProtocol symphony = (SymphonyProtocol) node.getProtocol(symphonyID);\r
+\r
+        if (symphony.loggedIntoNetwork != BootstrapStatus.OFFLINE) {\r
+            Transport transport = (Transport) node.getProtocol(transportID);\r
+\r
+            symphony.loggedIntoNetwork = BootstrapStatus.OFFLINE;\r
+\r
+            // Communicate that i'm leaving to the outgoing (that i point to) nodes\r
+            for (Node outgoingNode : symphony.longRangeLinksOutgoing) {\r
+                Message disconnectMsg = new Message(null, node, MessageType.DISCONNECT_LONG_RANGE_LINK);\r
+                transport.send(node, outgoingNode, disconnectMsg, pid);\r
+            }\r
+\r
+            // Communicate that i'm leaving to the incoming (that they point to me) nodes\r
+            for (Node incomingNode : symphony.longRangeLinksIncoming) {\r
+                Message unavailableMsg = new Message(null, node, MessageType.UNAVAILABLE_LONG_RANGE_LINK);\r
+                transport.send(node, incomingNode, unavailableMsg, pid);\r
+            }\r
+\r
+            // Communicate to my neighbours (short range links) that i'm leaving and i send to them the near neighbours\r
+            for (Tuple<Node, BootstrapStatus> leftTuple : symphony.leftShortRangeLinks) {\r
+                Message leaveMsg = new Message(symphony.rightShortRangeLinks.clone(), node, MessageType.LEAVE);\r
+                transport.send(node, leftTuple.x, leaveMsg, pid);\r
+            }\r
+\r
+            for (Tuple<Node, BootstrapStatus> rightTuple : symphony.rightShortRangeLinks) {\r
+                Message leaveMsg = new Message(symphony.leftShortRangeLinks.clone(), node, MessageType.LEAVE);\r
+                transport.send(node, rightTuple.x, leaveMsg, pid);\r
+            }\r
+\r
+            node.setFailState(Fallible.DEAD);\r
+        }\r
+    }\r
+\r
+    public void processEvent(Node node, int pid, Object event) {\r
+\r
+        Message msg = (Message) event;\r
+\r
+        SymphonyProtocol symphony = (SymphonyProtocol) node.getProtocol(symphonyID);\r
+        Transport transport = (Transport) node.getProtocol(transportID);\r
+\r
+        Collection<Tuple<Node, BootstrapStatus>> collection = null;\r
+        switch (msg.getType()) {\r
+            case JOIN:\r
+                // I send my  current neighbours to the entering node\r
+                collection = (Collection<Tuple<Node, BootstrapStatus>>) symphony.leftShortRangeLinks.clone();\r
+                collection.addAll((Collection<Tuple<Node, BootstrapStatus>>) symphony.rightShortRangeLinks.clone());\r
+                Message responseMsg = new Message(collection, node, MessageType.JOIN_RESPONSE);\r
+                transport.send(node, msg.getSourceNode(), responseMsg, pid);\r
+\r
+                /*\r
+                 * Update my neighbours list, adding the new one (for sure it is entering in the\r
+                 * left side)\r
+                 *\r
+                 * Put to "ONLINE_AND_ALL_NEIGHBOURS_OFFLINE" because maybe the bootstrap phase is\r
+                 * not terminated yet (ashyncronous communication)\r
+                 */\r
+                symphony.leftShortRangeLinks.add(new Tuple<Node, BootstrapStatus>(msg.getSourceNode(), BootstrapStatus.ONLINE_AND_ALL_NEIGHBOURS_OFFLINE));\r
+\r
+\r
+                fixNeighbours(node, symphony.leftShortRangeLinks);\r
+                break;\r
+            case JOIN_RESPONSE:\r
+\r
+                Collection<Tuple<Node, BootstrapStatus>> tupleCollection = (Collection<Tuple<Node, BootstrapStatus>>) msg.getBody();\r
+\r
+                /*\r
+                 *\r
+                 * My manager is a right neighbour. The manager is already inside the ring, boostrap\r
+                 * obliviously ok\r
+                 */\r
+                symphony.rightShortRangeLinks.add(new Tuple<Node, BootstrapStatus>(msg.getSourceNode(), BootstrapStatus.ONLINE));\r
+\r
+                // Set my neighbours in the correct position\r
+                for (Tuple<Node, BootstrapStatus> tuple : tupleCollection) {\r
+                    if (SymphonyProtocol.isLeftNeighbour(node, tuple.x)) {\r
+                        symphony.leftShortRangeLinks.add(tuple);\r
+                    } else {\r
+                        symphony.rightShortRangeLinks.add(tuple);\r
+                    }\r
+                }\r
+\r
+                fixNeighbours(node, symphony.leftShortRangeLinks);\r
+                fixNeighbours(node, symphony.rightShortRangeLinks);\r
+\r
+                // Update bootstrap status\r
+                checkBootstrapStatus(node);\r
+\r
+                // I send the refresh command such a way to exchange the views\r
+                refreshNeighbours(node);\r
+\r
+                // Update Long Range Links, because it's at the beginning is the same as adding k\r
+                updateLongRangeLinks(node);\r
+                break;\r
+            case UPDATE_NEIGHBOURS:\r
+\r
+                Collection<Tuple<Node, BootstrapStatus>> collectionCloned = ((Collection<Tuple<Node, BootstrapStatus>>) symphony.leftShortRangeLinks.clone());\r
+                collectionCloned.addAll(((Collection<Tuple<Node, BootstrapStatus>>) symphony.rightShortRangeLinks.clone()));\r
+\r
+                // Send my neighbours such a way it can also update itself\r
+                Message responseUpdateMsg = new Message(collectionCloned, node, MessageType.UPDATE_NEIGHBOURS_RESPONSE);\r
+                transport.send(node, msg.getSourceNode(), responseUpdateMsg, pid);\r
+\r
+                // Update my view with the new node\r
+                Tuple<Node, BootstrapStatus> neighbourTuple = new Tuple<Node, BootstrapStatus>(msg.getSourceNode(), (BootstrapStatus) msg.getBody());\r
+                if (SymphonyProtocol.isLeftNeighbour(node, msg.getSourceNode())) {\r
+                    collection = symphony.leftShortRangeLinks;\r
+                } else {\r
+                    collection = symphony.rightShortRangeLinks;\r
+                }\r
+                collection.add(neighbourTuple);\r
+\r
+                fixNeighbours(node, collection);\r
+                fixLookAheadMap(node);\r
+                break;\r
+            case UPDATE_NEIGHBOURS_RESPONSE:\r
+\r
+                Collection<Tuple<Node, BootstrapStatus>> responseCollection = (Collection<Tuple<Node, BootstrapStatus>>) msg.getBody();\r
+\r
+                for (Tuple<Node, BootstrapStatus> neighbourResponseTuple : responseCollection) {\r
+                    if (SymphonyProtocol.isLeftNeighbour(node, neighbourResponseTuple.x)) {\r
+                        collection = symphony.leftShortRangeLinks;\r
+                    } else {\r
+                        collection = symphony.rightShortRangeLinks;\r
+                    }\r
+                    collection.add(neighbourResponseTuple);\r
+                }\r
+\r
+                // Fix the neighbours number to the maximum allow and maybe remove myself from the list\r
+                fixNeighbours(node, symphony.leftShortRangeLinks);\r
+                fixNeighbours(node, symphony.rightShortRangeLinks);\r
+                fixLookAheadMap(node);\r
+                break;\r
+            case UPDATE_STATUS:\r
+            case UPDATE_STATUS_RESPONSE:\r
+\r
+                Node updNode = msg.getSourceNode();\r
+                BootstrapStatus updStatus = (BootstrapStatus) msg.getBody();\r
+\r
+                // I search the neighbour and i update its status\r
+                boolean founded = false;\r
+\r
+                // Try to see if it is on the left\r
+                for (Tuple<Node, BootstrapStatus> leftTuple : symphony.leftShortRangeLinks) {\r
+                    if (leftTuple.x.equals(updNode)) {\r
+                        symphony.leftShortRangeLinks.remove(leftTuple);\r
+                        symphony.leftShortRangeLinks.add(new Tuple<Node, BootstrapStatus>(updNode, updStatus));\r
+\r
+                        founded = true;\r
+                        break;\r
+                    }\r
+                }\r
+\r
+                // If it isn't on the left i try with the neighbours on the right\r
+                if (!founded) {\r
+                    for (Tuple<Node, BootstrapStatus> rightTuple : symphony.rightShortRangeLinks) {\r
+                        if (rightTuple.x.equals(updNode)) {\r
+                            symphony.rightShortRangeLinks.remove(rightTuple);\r
+                            symphony.rightShortRangeLinks.add(new Tuple<Node, BootstrapStatus>(updNode, updStatus));\r
+\r
+                            break;\r
+                        }\r
+                    }\r
+\r
+                    fixNeighbours(node, symphony.rightShortRangeLinks);\r
+                } else {\r
+                    fixNeighbours(node, symphony.leftShortRangeLinks);\r
+                }\r
+\r
+                checkBootstrapStatusAndAlert(node);\r
+\r
+                if (msg.getType() == MessageType.UPDATE_STATUS) {\r
+                    Message responseUpdStatus = new Message(symphony.loggedIntoNetwork, node, MessageType.UPDATE_STATUS_RESPONSE);\r
+                    transport.send(node, updNode, responseUpdStatus, pid);\r
+                }\r
+\r
+                break;\r
+            case REQUEST_LONG_RANGE_LINK:\r
+                MessageType responseType = MessageType.REJECT_LONG_RANGE_LINK;\r
+                if (symphony.longRangeLinksIncoming.size() < (2 * k)) {\r
+                    boolean added = symphony.longRangeLinksIncoming.add(msg.getSourceNode());\r
+                    if (added) {\r
+                        responseType = MessageType.ACCEPTED_LONG_RANGE_LINK;\r
+                    }\r
+                }\r
+                Message responseLongLinkMsg = new Message(null, node, responseType);\r
+                transport.send(node, msg.getSourceNode(), responseLongLinkMsg, pid);\r
+                break;\r
+            case ACCEPTED_LONG_RANGE_LINK:\r
+                nLink = n;\r
+                symphony.longRangeLinksOutgoing.add(msg.getSourceNode());\r
+                break;\r
+            case REJECT_LONG_RANGE_LINK:\r
+                if (currentAttempts > 0) {\r
+                    currentAttempts--;\r
+                    sendLongRangeLinkRequest(symphony, node);\r
+                }\r
+                break;\r
+            case DISCONNECT_LONG_RANGE_LINK:\r
+                symphony.longRangeLinksIncoming.remove(msg.getSourceNode());\r
+                symphony.lookAheadMap.put(msg.getSourceNode(), null);\r
+                break;\r
+            case UNAVAILABLE_LONG_RANGE_LINK:\r
+                symphony.longRangeLinksOutgoing.remove(msg.getSourceNode());\r
+                symphony.lookAheadMap.put(msg.getSourceNode(), null);\r
+                break;\r
+            case LEAVE:\r
+                Tuple<Node, BootstrapStatus> foundedTuple = null;\r
+\r
+                // Verify if the node that is leaving is a left neighbour\r
+                for (Tuple<Node, BootstrapStatus> leftTuple : symphony.leftShortRangeLinks) {\r
+                    if (leftTuple.x.equals(msg.getSourceNode())) {\r
+                        collection = symphony.leftShortRangeLinks;\r
+                        foundedTuple = leftTuple;\r
+                        break;\r
+                    }\r
+                }\r
+\r
+                // Verify if the node that is leaving is a right neighbour\r
+                if (collection == null) {\r
+                    for (Tuple<Node, BootstrapStatus> rightTuple : symphony.rightShortRangeLinks) {\r
+                        if (rightTuple.x.equals(msg.getSourceNode())) {\r
+                            collection = symphony.rightShortRangeLinks;\r
+                            foundedTuple = rightTuple;\r
+                            break;\r
+                        }\r
+                    }\r
+                }\r
+\r
+                // if i've found the neighbour i remove it and i add to myself its neighbours\r
+                if (collection != null) {\r
+                    collection.addAll((Collection<Tuple<Node, BootstrapStatus>>) msg.getBody());\r
+                    collection.remove(foundedTuple);\r
+                    fixNeighbours(node, collection);\r
+\r
+                    // Update status and ready to send an alert in case i'm out of the ring\r
+                    checkBootstrapStatusAndAlert(node);\r
+                }\r
+                break;\r
+            case KEEP_ALIVE:\r
+                Set<Double>[] lookAheadSetArray = new LinkedHashSet[2];\r
+\r
+                /*\r
+                 * Check if the contacting node is doing lookAhead and in case of affirmative answer\r
+                 * i provide to it the long range link identifiers (according to my routing mode)\r
+                 */\r
+                if ((Boolean) msg.getBody()) {\r
+                    int i = 0;\r
+                    Iterable[] iterableArray;\r
+                    if (symphony.bidirectionalRouting) {\r
+                        iterableArray = new Iterable[]{symphony.longRangeLinksOutgoing, symphony.longRangeLinksIncoming};\r
+                    } else {\r
+                        iterableArray = new Iterable[]{symphony.longRangeLinksOutgoing};\r
+                    }\r
+\r
+                    for (Iterable<Node> iterable : iterableArray) {\r
+                        lookAheadSetArray[i] = new LinkedHashSet<Double>();\r
+                        Set<Double> lookAheadSet = lookAheadSetArray[i];\r
+                        Iterator<Node> it = iterable.iterator();\r
+                        while (it.hasNext()) {\r
+                            Node longLinkNode = it.next();\r
+                            lookAheadSet.add(((SymphonyProtocol) longLinkNode.getProtocol(symphonyID)).getIdentifier());\r
+                        }\r
+                        i++;\r
+                    }\r
+                }\r
+\r
+                transport.send(node, msg.getSourceNode(), new Message(lookAheadSetArray, node, MessageType.KEEP_ALIVE_RESPONSE), pid);\r
+                break;\r
+            case KEEP_ALIVE_RESPONSE:\r
+                // Reset the counter to 0\r
+                keepAliveMap.put(msg.getSourceNode(), 0);\r
+\r
+                if (symphony.lookAhead) {\r
+                    symphony.lookAheadMap.put(msg.getSourceNode(), (Set<Double>[]) msg.getBody());\r
+                }\r
+\r
+                break;\r
+        }\r
+    }\r
+\r
+    /**\r
+     *\r
+     * Update the status and communicate immediately to the neighbours if the node is gone out from\r
+     * the ring (and before it was inside)\r
+     *\r
+     * @param node\r
+     */\r
+    private void checkBootstrapStatusAndAlert(Node node) {\r
+        SymphonyProtocol symphony = (SymphonyProtocol) node.getProtocol(symphonyID);\r
+        BootstrapStatus beforeStatus = symphony.loggedIntoNetwork;\r
+\r
+        checkBootstrapStatus(node);\r
+\r
+        // Instead of waiting that the update happens periodically i do it now because i'm out of the ring and before i wasn't\r
+        if (symphony.loggedIntoNetwork != beforeStatus && !symphony.isBootstrapped()) {\r
+            updateBootstrapStatusNeighbours(node, true);\r
+        }\r
+    }\r
+\r
+    private void fixNeighbours(Node node, Collection<Tuple<Node, BootstrapStatus>> neighbours) {\r
+\r
+        SymphonyProtocol symphony = (SymphonyProtocol) node.getProtocol(symphonyID);\r
+\r
+        // Remove duplicates, remove that ones that are in an obsolete status\r
+        Collection<Tuple<Node, BootstrapStatus>> removedNeighbours = new LinkedHashSet<Tuple<Node, BootstrapStatus>>();\r
+        for (Tuple<Node, BootstrapStatus> tuple : neighbours) {\r
+\r
+            // Remove myself from the neighbours list\r
+            if (tuple.x.equals(node)) {\r
+                removedNeighbours.add(tuple);\r
+                continue;\r
+            }\r
+\r
+            EnumSet<BootstrapStatus> status = EnumSet.allOf(BootstrapStatus.class);\r
+            status.remove(tuple.y);\r
+\r
+            for (BootstrapStatus opposite : status) {\r
+                Tuple<Node, BootstrapStatus> oppositeNeighbour = new Tuple<Node, BootstrapStatus>(tuple.x, opposite);\r
+                if (neighbours.contains(oppositeNeighbour)) {\r
+                    if (tuple.y != BootstrapStatus.ONLINE) {\r
+                        removedNeighbours.add(new Tuple<Node, BootstrapStatus>(tuple.x, BootstrapStatus.OFFLINE));\r
+                        if (opposite == BootstrapStatus.ONLINE) {\r
+                            removedNeighbours.add(new Tuple<Node, BootstrapStatus>(tuple.x, BootstrapStatus.ONLINE_AND_ALL_NEIGHBOURS_OFFLINE));\r
+                        }\r
+                    }\r
+                }\r
+            }\r
+        }\r
+        neighbours.removeAll(removedNeighbours);\r
+\r
+        /*\r
+         *\r
+         * I count the neighbours that are in the ONLINE status but before i remove the ones that\r
+         * are gone in timeout during the keep-alive procedure because can be someone that is old\r
+         * but not remove from the exchanging views (UPDATE_NEIGHBOURS) procedure and are not\r
+         * effectively online. To do anyway the possibility to the node to join again i decrease its\r
+         * timeout value. This only if the node is ONLINE and so i'm really interested that it is ok\r
+         * for the routing.\r
+         *\r
+         */\r
+        int onlineNeighbours = 0;\r
+        for (Tuple<Node, BootstrapStatus> tuple : neighbours) {\r
+\r
+            Integer value = keepAliveMap.get(tuple.x);\r
+            if (value != null && value >= nTimeout && tuple.y == BootstrapStatus.ONLINE) {\r
+                keepAliveMap.put(tuple.x, value - 1);\r
+                removedNeighbours.add(tuple);\r
+            } else {\r
+\r
+                if (tuple.y == BootstrapStatus.ONLINE) {\r
+                    onlineNeighbours++;\r
+                }\r
+            }\r
+        }\r
+        neighbours.removeAll(removedNeighbours);\r
+\r
+        // Fix the neighbours number to the maximum allowed\r
+        SymphonyNodeComparator comparator = new SymphonyNodeComparator(symphonyID, node);\r
+        AdapterSymphonyNodeComparator adapterComparator = new AdapterSymphonyNodeComparator(comparator);\r
+        while (neighbours.size() > symphony.numberShortRangeLinksPerSide) {\r
+            Tuple<Node, BootstrapStatus> distantTuple = Collections.max(neighbours, adapterComparator);\r
+\r
+            // Mantain the link with the ring\r
+            if (distantTuple.y == BootstrapStatus.ONLINE) {\r
+                if (onlineNeighbours > 1) {\r
+                    neighbours.remove(distantTuple);\r
+                    onlineNeighbours--;\r
+                } else {\r
+                    /*\r
+                     * If will be only one neighbour that is online i save it and i'm going to\r
+                     * eliminate another one (for sure it'll be not online)\r
+                     *\r
+                     */\r
+                    Tuple<Node, BootstrapStatus> backupOnlineNeighbour = distantTuple;\r
+                    neighbours.remove(backupOnlineNeighbour);\r
+                    distantTuple = Collections.max(neighbours, adapterComparator);\r
+                    neighbours.add(backupOnlineNeighbour);\r
+                    neighbours.remove(distantTuple);\r
+                }\r
+\r
+            } else {\r
+                neighbours.remove(distantTuple);\r
+            }\r
+        }\r
+    }\r
+\r
+    @Override\r
+    public Object clone() {\r
+        SymphonyNetworkManager dolly = new SymphonyNetworkManager(prefix);\r
+        return dolly;\r
+    }\r
+\r
+    public void nextCycle(Node node, int protocolID) {\r
+\r
+        if (node.isUp()) {\r
+\r
+            // Update the estimated network size\r
+            updateN(node);\r
+\r
+            // Update the estimated K\r
+            updateK(node);\r
+\r
+            // Update the bootstrap status of my neighbours that were joining the ring\r
+            updateBootstrapStatusNeighbours(node, false);\r
+\r
+            // Refresh the neighbours views\r
+            refreshNeighbours(node);\r
+\r
+            // I send and check the connection status of the neighbours\r
+            keepAlive(node);\r
+\r
+            // Update the bootstrap status\r
+            checkBootstrapStatus(node);\r
+\r
+            // If it's active i check the Relinking criteria\r
+            if (relinkingProtocolActivated) {\r
+                reLinkingProtocol(node);\r
+            }\r
+\r
+            // Update the long range links (conservative)\r
+            updateLongRangeLinks(node);\r
+        }\r
+    }\r
+\r
+    /**\r
+     *\r
+     * @param allNeighbours true, communicate/receive the status update from all the neighbours.\r
+     * false, communicate/receive the status update only from the neighbours that are NOT ONLINE\r
+     *\r
+     */\r
+    private void updateBootstrapStatusNeighbours(Node node, boolean allNeighbours) {\r
+        SymphonyProtocol symphony = (SymphonyProtocol) node.getProtocol(symphonyID);\r
+        Transport transport = (Transport) node.getProtocol(transportID);\r
+\r
+        Collection<Tuple<Node, BootstrapStatus>> collection = new LinkedHashSet<Tuple<Node, BootstrapStatus>>();\r
+        collection.addAll(symphony.leftShortRangeLinks);\r
+        collection.addAll(symphony.rightShortRangeLinks);\r
+\r
+        for (Tuple<Node, BootstrapStatus> neighbourTuple : collection) {\r
+            if (allNeighbours || neighbourTuple.y != BootstrapStatus.ONLINE) {\r
+                Message msg = new Message(symphony.loggedIntoNetwork, node, MessageType.UPDATE_STATUS);\r
+                transport.send(node, neighbourTuple.x, msg, pid);\r
+            }\r
+        }\r
+    }\r
+\r
+    private void updateN(Node node) {\r
+        NetworkSizeEstimatorProtocolInterface networkEstimator = (NetworkSizeEstimatorProtocolInterface) node.getProtocol(networkEstimatorID);\r
+        n = networkEstimator.getNetworkSize(node);\r
+        if (n <= 0) {\r
+            n = DEFAULT_N;\r
+        }\r
+    }\r
+\r
+    /**\r
+     * Update the K value with the current expectation of the network size\r
+     */\r
+    private void updateK(Node node) {\r
+\r
+        SymphonyProtocol symphony = (SymphonyProtocol) node.getProtocol(symphonyID);\r
+        if (!symphony.fixedLongRangeLinks) {\r
+            k = (int) Math.ceil(Math.log(n) / Math.log(2));\r
+\r
+            if (k <= 0) {\r
+                k = DEFAULT_K;\r
+            }\r
+        } else {\r
+            k = symphony.numberFixedLongRangeLinks;\r
+        }\r
+    }\r
+\r
+    private void refreshNeighbours(Node node) {\r
+        SymphonyProtocol symphony = (SymphonyProtocol) node.getProtocol(symphonyID);\r
+        Transport transport = (Transport) node.getProtocol(transportID);\r
+\r
+        for (Tuple<Node, BootstrapStatus> leftTuple : symphony.leftShortRangeLinks) {\r
+            Node leftNode = leftTuple.x;\r
+            Message updateNeighbourMsg = new Message(symphony.loggedIntoNetwork, node, MessageType.UPDATE_NEIGHBOURS);\r
+            transport.send(node, leftNode, updateNeighbourMsg, pid);\r
+        }\r
+\r
+        for (Tuple<Node, BootstrapStatus> rightTuple : symphony.rightShortRangeLinks) {\r
+            Node rightNode = rightTuple.x;\r
+            Message updateNeighbourMsg = new Message(symphony.loggedIntoNetwork, node, MessageType.UPDATE_NEIGHBOURS);\r
+            transport.send(node, rightNode, updateNeighbourMsg, pid);\r
+        }\r
+    }\r
+\r
+    /**\r
+     * Method to update the (connection) status of the node. Perform the update to the "up" so:\r
+     * OFFLINE -> ONLINE_AND_ALL_NEIGHBOURS_OFFLINE -> ONLINE\r
+     *\r
+     * and to the "down" only: ONLINE -> ONLINE_AND_ALL_NEIGHBOURS_OFFLINE\r
+     *\r
+     * @param node\r
+     */\r
+    private void checkBootstrapStatus(Node node) {\r
+        SymphonyProtocol symphony = (SymphonyProtocol) node.getProtocol(symphonyID);\r
+\r
+        if (symphony.loggedIntoNetwork != BootstrapStatus.OFFLINE) {\r
+\r
+            symphony.loggedIntoNetwork = BootstrapStatus.ONLINE_AND_ALL_NEIGHBOURS_OFFLINE;\r
+\r
+            // Check if i'm inside the ring and i'm able to do routing\r
+            if (!symphony.leftShortRangeLinks.isEmpty() && !symphony.rightShortRangeLinks.isEmpty()) {\r
+\r
+                boolean leftOk = false;\r
+                for (Tuple<Node, BootstrapStatus> leftTuple : symphony.leftShortRangeLinks) {\r
+                    if (leftTuple.y == BootstrapStatus.ONLINE) {\r
+                        leftOk = true;\r
+                        break;\r
+                    }\r
+                }\r
+\r
+                if (leftOk) {\r
+                    for (Tuple<Node, BootstrapStatus> rightTuple : symphony.rightShortRangeLinks) {\r
+                        if (rightTuple.y == BootstrapStatus.ONLINE) {\r
+                            symphony.loggedIntoNetwork = BootstrapStatus.ONLINE;\r
+                            break;\r
+                        }\r
+                    }\r
+                }\r
+            }\r
+        }\r
+    }\r
+\r
+    /**\r
+     * Remove the possible wrong entries from the lookAhead table\r
+     */\r
+    private void fixLookAheadMap(Node node) {\r
+        SymphonyProtocol symphony = (SymphonyProtocol) node.getProtocol(symphonyID);\r
+        for (Tuple<Node, BootstrapStatus> tuple : symphony.leftShortRangeLinks) {\r
+            symphony.lookAheadMap.put(tuple.x, null);\r
+        }\r
+        for (Tuple<Node, BootstrapStatus> tuple : symphony.rightShortRangeLinks) {\r
+            symphony.lookAheadMap.put(tuple.x, null);\r
+        }\r
+    }\r
+\r
+    /**\r
+     * Sent keep-alive messages to verify if the links still online\r
+     *\r
+     * if enable the lookAhead mode i require the neighbours list from my neighbours (1-lookAhead).\r
+     *\r
+     * Note: I don't reuse the UPDATE_STATUS messages because i want to mantain separate the\r
+     * semantic and have more clear source code\r
+     */\r
+    private void keepAlive(Node node) {\r
+\r
+        SymphonyProtocol symphony = (SymphonyProtocol) node.getProtocol(symphonyID);\r
+        Transport transport = (Transport) node.getProtocol(transportID);\r
+\r
+        // Send and check for the long range links (both incoming and outgoing)\r
+        for (Iterable<Node> iterable : new Iterable[]{symphony.longRangeLinksOutgoing, symphony.longRangeLinksIncoming}) {\r
+            Iterator<Node> longLinksIterator = iterable.iterator();\r
+            while (longLinksIterator.hasNext()) {\r
+                Node longLinkNode = longLinksIterator.next();\r
+                Integer value = keepAliveMap.get(longLinkNode);\r
+                if (value == null) {\r
+                    value = 0;\r
+                }\r
+\r
+                /*\r
+                 * Verify if i reached the sufficient time of sending and not receiving an answer\r
+                 * and so i can consider that node as disconnected\r
+                 */\r
+                if (value >= nTimeout) {\r
+                    symphony.lookAheadMap.put(longLinkNode, null); // Do it anyway if it's enabled the lookAhead or not\r
+                    longLinksIterator.remove();\r
+                } else {\r
+                    keepAliveMap.put(longLinkNode, value + 1);\r
+\r
+                    Message keepAliveMsg = new Message(symphony.lookAhead, node, MessageType.KEEP_ALIVE);\r
+                    transport.send(node, longLinkNode, keepAliveMsg, pid);\r
+                }\r
+            }\r
+        }\r
+\r
+        // Send and check for the short links\r
+        for (Iterable<Tuple<Node, BootstrapStatus>> iterable : new Iterable[]{symphony.rightShortRangeLinks, symphony.leftShortRangeLinks}) {\r
+            Iterator<Tuple<Node, BootstrapStatus>> shortLinksIterator = iterable.iterator();\r
+            while (shortLinksIterator.hasNext()) {\r
+                Node shortLinkNode = shortLinksIterator.next().x;\r
+                Integer value = keepAliveMap.get(shortLinkNode);\r
+                if (value == null) {\r
+                    value = 0;\r
+                }\r
+\r
+                // the same as above\r
+                if (value >= nTimeout) {\r
+                    shortLinksIterator.remove();\r
+                } else {\r
+                    keepAliveMap.put(shortLinkNode, value + 1);\r
+\r
+                    // LookAhead is not to be performed to the short links!\r
+                    Message keepAliveMsg = new Message(false, node, MessageType.KEEP_ALIVE);\r
+                    transport.send(node, shortLinkNode, keepAliveMsg, pid);\r
+                }\r
+            }\r
+        }\r
+    }\r
+\r
+    /**\r
+     * Implement the Re-Linking criteria of the Long Range Links. It does the complete refresh. The\r
+     * repopulation is done through the 'updateLongRangeLinks' method.\r
+     */\r
+    private void reLinkingProtocol(Node node) {\r
+        // I do the check only if i succeed at least one time to create a long range link\r
+        if (nLink > 0) {\r
+            double criterionValue = n / nLink;\r
+\r
+            if (!(criterionValue >= relinkingLowerBound && criterionValue <= relinkingUpperBound)) {\r
+\r
+                /*\r
+                 * Not explicitly precised in the paper: if i haven't created a new link i update\r
+                 * anyway nLink because can happen a special case that i will not be able to create\r
+                 * links because the reLinkingProtocol procedure is "faster".\r
+                 */\r
+                nLink = n;\r
+\r
+                SymphonyProtocol symphony = (SymphonyProtocol) node.getProtocol(symphonyID);\r
+                Transport transport = (Transport) node.getProtocol(transportID);\r
+\r
+                // Communicate to the all Outgoing Long Range Links that they aren't anymore\r
+                for (Node longRangeLinkOutgoingNode : symphony.longRangeLinksOutgoing) {\r
+                    Message disconnectMsg = new Message(null, node, MessageType.DISCONNECT_LONG_RANGE_LINK);\r
+                    transport.send(node, longRangeLinkOutgoingNode, disconnectMsg, pid);\r
+                }\r
+\r
+                symphony.longRangeLinksOutgoing.clear();\r
+            }\r
+        }\r
+    }\r
+\r
+    public int getK() {\r
+        return k;\r
+    }\r
+\r
+    public int getN() {\r
+        return n;\r
+    }\r
+}\r
diff --git a/contrib/psg/src/example/symphony/SymphonyNodeComparator.java b/contrib/psg/src/example/symphony/SymphonyNodeComparator.java
new file mode 100644 (file)
index 0000000..e5a17d2
--- /dev/null
@@ -0,0 +1,51 @@
+package example.symphony;\r
+\r
+import java.util.Comparator;\r
+import java.util.logging.Level;\r
+import java.util.logging.Logger;\r
+import peersim.core.Node;\r
+\r
+/**\r
+ * Comparator that measure the relative distance from a target node\r
+ *\r
+ * @author Andrea Esposito <and1989@gmail.com>\r
+ */\r
+public class SymphonyNodeComparator implements Comparator<Node> {\r
+\r
+    private final int symphonyID;\r
+    private double target;\r
+\r
+    public SymphonyNodeComparator(int symphonyID) {\r
+        this.symphonyID = symphonyID;\r
+    }\r
+\r
+    public SymphonyNodeComparator(int symphonyID, double target) {\r
+        this(symphonyID);\r
+        this.target = target;\r
+    }\r
+\r
+    public SymphonyNodeComparator(int symphonyID, Node targetNode) {\r
+        this(symphonyID);\r
+        SymphonyProtocol symphony = (SymphonyProtocol) targetNode.getProtocol(symphonyID);\r
+        this.target = symphony.getIdentifier();\r
+    }\r
+\r
+    public int compare(Node o1, Node o2) {\r
+\r
+        SymphonyProtocol symphony1 = (SymphonyProtocol) o1.getProtocol(symphonyID);\r
+        SymphonyProtocol symphony2 = (SymphonyProtocol) o2.getProtocol(symphonyID);\r
+\r
+        Double identifier1 = symphony1.getIdentifier();\r
+        Double identifier2 = symphony2.getIdentifier();\r
+\r
+        Double distance1 = Math.abs(target - identifier1) % 1;\r
+        Double distance2 = Math.abs(target - identifier2) % 1;\r
+\r
+        identifier1 = Math.min(1.0 - distance1, distance1);\r
+        identifier2 = Math.min(1.0 - distance2, distance2);\r
+\r
+        Logger.getLogger(SymphonyNodeComparator.class.getName()).log(Level.FINEST, "id1= " + symphony1.getIdentifier() + " target= " + target + " id2= " + symphony2.getIdentifier() + " res= " + identifier1.compareTo(identifier2));\r
+\r
+        return identifier1.compareTo(identifier2);\r
+    }\r
+}\r
diff --git a/contrib/psg/src/example/symphony/SymphonyNodeInizializer.java b/contrib/psg/src/example/symphony/SymphonyNodeInizializer.java
new file mode 100644 (file)
index 0000000..ec5dc68
--- /dev/null
@@ -0,0 +1,59 @@
+package example.symphony;\r
+\r
+import java.util.logging.Level;\r
+import java.util.logging.Logger;\r
+import peersim.config.Configuration;\r
+import peersim.core.Network;\r
+import peersim.core.Node;\r
+import peersim.dynamics.NodeInitializer;\r
+\r
+/**\r
+ *\r
+ * @author Andrea Esposito <and1989@gmail.com>\r
+ */\r
+public class SymphonyNodeInizializer implements NodeInitializer {\r
+\r
+    private static final String PAR_NETMANAGER = "symphonynetworkmanager";\r
+    private static final String PAR_SYMPHONY = "symphony";\r
+    private static final String PAR_BOOTNODE = "bootstrapnode";\r
+    private final int networkManagerID;\r
+    private final int symphonyID;\r
+    private final int indexBootstrapNode;\r
+\r
+    public SymphonyNodeInizializer(String prefix) {\r
+\r
+        networkManagerID = Configuration.getPid(prefix + "." + PAR_NETMANAGER);\r
+        indexBootstrapNode = Configuration.getInt(prefix + "." + PAR_BOOTNODE, 0);\r
+        symphonyID = Configuration.getPid(prefix + "." + PAR_SYMPHONY);\r
+    }\r
+\r
+    @Override\r
+    public void initialize(Node node) {\r
+        int indexRealBootstrapNode = indexBootstrapNode;\r
+        Node realBootstrapNode = Network.get(indexBootstrapNode);\r
+        SymphonyNetworkManager symphonyNetworkManager = (SymphonyNetworkManager) node.getProtocol(networkManagerID);\r
+        SymphonyProtocol symphony = (SymphonyProtocol) realBootstrapNode.getProtocol(symphonyID);\r
+\r
+        boolean joinSent;\r
+        do {\r
+            try {\r
+                while (!symphony.isBootstrapped() || !realBootstrapNode.isUp()) {\r
+                    indexRealBootstrapNode = (indexRealBootstrapNode + 1) % Network.size();\r
+                    realBootstrapNode = Network.get(indexRealBootstrapNode);\r
+                    symphony = (SymphonyProtocol) realBootstrapNode.getProtocol(symphonyID);\r
+\r
+                    if (indexRealBootstrapNode == indexBootstrapNode) {\r
+                        Logger.getLogger(SymphonyNodeInizializer.class.getName()).log(Level.WARNING, "No node ONLINE. Impossible to do the network bootstrap.");\r
+                        return;\r
+                    }\r
+                }\r
+\r
+                symphonyNetworkManager.join(node, realBootstrapNode);\r
+                joinSent = true;\r
+            } catch (RoutingException ex) {\r
+                Logger.getLogger(SymphonyNodeInizializer.class.getName()).log(Level.SEVERE, "Join Issue");\r
+                joinSent = false;\r
+            }\r
+        } while (!joinSent);\r
+    }\r
+}\r
diff --git a/contrib/psg/src/example/symphony/SymphonyProtocol.java b/contrib/psg/src/example/symphony/SymphonyProtocol.java
new file mode 100644 (file)
index 0000000..478f81e
--- /dev/null
@@ -0,0 +1,530 @@
+package example.symphony;\r
+\r
+import java.lang.ref.SoftReference;\r
+import java.util.*;\r
+import java.util.logging.Level;\r
+import java.util.logging.Logger;\r
+\r
+import example.symphony.Message.MessageType;\r
+import peersim.config.Configuration;\r
+import peersim.core.CommonState;\r
+import peersim.core.Node;\r
+import peersim.edsim.EDProtocol;\r
+import peersim.transport.Transport;\r
+\r
+/**\r
+ *\r
+ * @author Andrea Esposito <and1989@gmail.com>\r
+ */\r
+public class SymphonyProtocol implements EDProtocol {\r
+\r
+    private static final String PAR_SHORT_LINK = "shortlink";\r
+    private static final String PAR_LONG_LINK = "longlink";\r
+    private static final String PAR_TRANSP = "transport";\r
+    private static final String PAR_ROUTING = "routing";\r
+    private static final String PAR_LOOKAHEAD = "lookahead";\r
+    private static Set<Double> allIdentifier = new HashSet<Double>();\r
+    private final String prefix;\r
+    private static int pid;\r
+    private final int transportID;\r
+    private final double identifier;\r
+    public final int sequentialIdentifier;\r
+    private static int sequentialCounter = 0;\r
+    public final int numberShortRangeLinksPerSide;\r
+    public final boolean bidirectionalRouting;\r
+    public final boolean lookAhead;\r
+    public final boolean fixedLongRangeLinks;\r
+    public final int numberFixedLongRangeLinks;\r
+    public LinkedHashSet<Node> longRangeLinksOutgoing;\r
+    public LinkedHashSet<Node> longRangeLinksIncoming;\r
+    public LinkedHashSet<Tuple<Node, BootstrapStatus>> rightShortRangeLinks;\r
+    public LinkedHashSet<Tuple<Node, BootstrapStatus>> leftShortRangeLinks;\r
+    /**\r
+     * Array Contract: at position 0 -> OutgoingLongRangeLinks, 1 -> IncomingLongRangeLinks\r
+     */\r
+    public final LinkedHashMap<Node, Set<Double>[]> lookAheadMap;\r
+    private HashMap<Double, Handler> mapHandler;\r
+    /**\r
+     * IDs Set to verify if there are cycles\r
+     */\r
+    private Set<Long> messageHistoryID;\r
+    /**\r
+     *\r
+     * Tuple chronology that contains: <received message, the possible answer message>\r
+     *\r
+     * I use SoftReference as a trade off between memory usage and accurancy\r
+     */\r
+    private Set<SoftReference<Tuple<Message, Message>>> messageHistory;\r
+    private static boolean firstPrintConfig = true;\r
+\r
+    public enum BootstrapStatus {\r
+\r
+        NEW, OFFLINE, ONLINE_AND_ALL_NEIGHBOURS_OFFLINE, ONLINE\r
+    }\r
+    public BootstrapStatus loggedIntoNetwork;\r
+\r
+    public SymphonyProtocol(String prefix) {\r
+\r
+        this.prefix = prefix;\r
+        pid = Configuration.lookupPid(prefix.replaceAll("protocol.", ""));\r
+        transportID = Configuration.getPid(prefix + "." + PAR_TRANSP);\r
+        numberShortRangeLinksPerSide = Configuration.getInt(prefix + "." + PAR_SHORT_LINK, 2) / 2;\r
+        bidirectionalRouting = !Configuration.getString(prefix + "." + PAR_ROUTING, "bidirectional").toLowerCase().equals("unidirectional");\r
+        lookAhead = !Configuration.getString(prefix + "." + PAR_LOOKAHEAD, "on").toLowerCase().equals("off");\r
+        numberFixedLongRangeLinks = Configuration.getInt(prefix + "." + PAR_LONG_LINK, -1);\r
+        fixedLongRangeLinks = numberFixedLongRangeLinks >= 0;\r
+\r
+        longRangeLinksOutgoing = new LinkedHashSet<Node>();\r
+        longRangeLinksIncoming = new LinkedHashSet<Node>();\r
+        rightShortRangeLinks = new LinkedHashSet<Tuple<Node, BootstrapStatus>>();\r
+        leftShortRangeLinks = new LinkedHashSet<Tuple<Node, BootstrapStatus>>();\r
+        lookAheadMap = new LinkedHashMap<Node, Set<Double>[]>();\r
+\r
+        identifier = generateUniqueIdentifier();\r
+        sequentialIdentifier = sequentialCounter++;\r
+\r
+        mapHandler = new HashMap<Double, Handler>();\r
+\r
+        messageHistoryID = new HashSet<Long>();\r
+        messageHistory = new LinkedHashSet<SoftReference<Tuple<Message, Message>>>();\r
+        loggedIntoNetwork = BootstrapStatus.NEW;\r
+\r
+        printConfig();\r
+    }\r
+\r
+    private void printConfig() {\r
+\r
+        if (firstPrintConfig) {\r
+            firstPrintConfig = false;\r
+            System.out.println(SymphonyProtocol.class.getSimpleName() + " Configuration:");\r
+            System.out.println("- Number of short range links per side: " + numberShortRangeLinksPerSide);\r
+            System.out.println("- Number of long range links: " + (fixedLongRangeLinks ? numberFixedLongRangeLinks : "log(n)"));\r
+            System.out.println("- Routing mode: " + (bidirectionalRouting ? "Bidirectional" : "Unidirectional"));\r
+            System.out.println("- LookAhead status: " + (lookAhead ? "ON" : "OFF"));\r
+            System.out.println("-------------------------------\n");\r
+        }\r
+    }\r
+\r
+    /**\r
+     *\r
+     * Method to identify the next node that has to be contacted. It's going to be used the mode\r
+     * that is described into the configuration file\r
+     */\r
+    public Node getCandidateForRouting(double identifierToRoute) throws RoutingException {\r
+        if (bidirectionalRouting) {\r
+            return getCandidateForBidirectionalRoute(identifierToRoute);\r
+        } else {\r
+            return getCandidateForUnidirectionalRoute(identifierToRoute);\r
+        }\r
+    }\r
+\r
+    /**\r
+     *\r
+     * Method to individuate the next node that as to be contacted through Unidirectional Routing\r
+     * mode\r
+     */\r
+    public Node getCandidateForUnidirectionalRoute(double identifierToRoute) throws RoutingException {\r
+\r
+        LinkedHashSet<Node> allLinks = new LinkedHashSet<Node>();\r
+        Node manager = putShortRangeLinksIntoContainerForRouting(allLinks, identifierToRoute);\r
+\r
+        if (manager != null) {\r
+            return manager;\r
+        }\r
+\r
+        allLinks.addAll(longRangeLinksOutgoing);\r
+\r
+        return findClosestNode(identifierToRoute, allLinks, true);\r
+    }\r
+\r
+    /**\r
+     * Method to individuate the next node that as to be contacted through Bidirectional Routing\r
+     * mode\r
+     */\r
+    public Node getCandidateForBidirectionalRoute(double identifierToRoute) throws RoutingException {\r
+\r
+        LinkedHashSet<Node> allLinks = new LinkedHashSet<Node>();\r
+        Node manager = putShortRangeLinksIntoContainerForRouting(allLinks, identifierToRoute);\r
+\r
+        if (manager != null) {\r
+            return manager;\r
+        }\r
+\r
+        allLinks.addAll(longRangeLinksOutgoing);\r
+        allLinks.addAll(longRangeLinksIncoming);\r
+\r
+        return findClosestNode(identifierToRoute, allLinks, false);\r
+    }\r
+\r
+    /**\r
+     * @return Null if it is NOT found the manager. Node if it is found.\r
+     */\r
+    private Node putShortRangeLinksIntoContainerForRouting(Set<Node> container, double identifierToRoute) {\r
+        for (Tuple<Node, BootstrapStatus> rightTuple : rightShortRangeLinks) {\r
+            if (rightTuple.y == BootstrapStatus.ONLINE) {\r
+                container.add(rightTuple.x);\r
+            }\r
+        }\r
+\r
+        if (!container.isEmpty()) {\r
+\r
+            // Special case: i verify if the neighbour at my right (ONLINE) is the manager\r
+            SymphonyNodeComparator comparator = new SymphonyNodeComparator(pid, identifier);\r
+            Node nearRightNeighbour = Collections.min(container, comparator);\r
+            if (nearRightNeighbour != null) {\r
+                SymphonyProtocol symphony = (SymphonyProtocol) nearRightNeighbour.getProtocol(pid);\r
+                if (!isLeftNeighbour(identifier, identifierToRoute) && isLeftNeighbour(symphony.getIdentifier(), identifierToRoute)) {\r
+                    return nearRightNeighbour;\r
+                }\r
+            }\r
+        }\r
+\r
+        for (Tuple<Node, BootstrapStatus> leftTuple : leftShortRangeLinks) {\r
+            if (leftTuple.y == BootstrapStatus.ONLINE) {\r
+                container.add(leftTuple.x);\r
+            }\r
+        }\r
+\r
+        return null;\r
+    }\r
+\r
+    /**\r
+     *\r
+     * Individuates effectively the next candidate for the routing. Checks if the lookahead is\r
+     * activated and in case of affirmative answer it's going to use that information.\r
+     *\r
+     * @param identifierToRoute Identifier to reach\r
+     * @param container Candidate Nodes Container\r
+     * @param clockwise true, does unidirectional routing. false, does bidirectional routing.\r
+     * @return The nearest node to reach identifierToRoute\r
+     * @throws RoutingException Throw in case no candidate is found\r
+     */\r
+    public Node findClosestNode(final double identifierToRoute, final Iterable<Node> container, final boolean clockwise) throws RoutingException {\r
+        Node ret = null;\r
+        double min = Double.MAX_VALUE;\r
+\r
+        for (Node node : container) {\r
+            SymphonyProtocol symphonyNodeContainer = (SymphonyProtocol) node.getProtocol(pid);\r
+            double realCandidateIdentifier = symphonyNodeContainer.getIdentifier();\r
+\r
+            Set<Double> candidateIdentifierSet = new LinkedHashSet<Double>();\r
+            candidateIdentifierSet.add(realCandidateIdentifier);\r
+\r
+            boolean lookAheadClockwise = true;\r
+\r
+            /*\r
+             *\r
+             * If lookahead is activated add all the reachable identifiers. No checks are performed\r
+             * on the node type (short/long) because at maximum the map return null.\r
+             */\r
+            if (lookAhead) {\r
+                Set<Double>[] lookAheadIdentifierSetArray = lookAheadMap.get(node);\r
+\r
+                if (lookAheadIdentifierSetArray != null) {\r
+                    Set<Double> lookAheadIdentifierSet = lookAheadIdentifierSetArray[0];\r
+\r
+                    if (lookAheadIdentifierSet == null) {\r
+                        lookAheadIdentifierSet = new LinkedHashSet<Double>();\r
+                    }\r
+\r
+                    /*\r
+                     *\r
+                     * If bidirectional routing is going to be performed so i put into account also\r
+                     * the Incoming Long Range Links of the current neighbour\r
+                     */\r
+                    if (bidirectionalRouting && lookAheadIdentifierSetArray[1] != null) {\r
+                        lookAheadIdentifierSet.addAll(lookAheadIdentifierSetArray[1]);\r
+                        lookAheadClockwise = false;\r
+                    }\r
+\r
+                    if (!lookAheadIdentifierSet.isEmpty()) {\r
+                        candidateIdentifierSet.addAll(lookAheadIdentifierSet);\r
+                    }\r
+                }\r
+            }\r
+\r
+            for (Double candidateIdentifier : candidateIdentifierSet) {\r
+                // if it is a my neighbour i use my routing mode instead if it is a looAhead one i use its routing mode\r
+                boolean currentClockwise = candidateIdentifier.equals(realCandidateIdentifier) ? clockwise : lookAheadClockwise;\r
+\r
+                double distance = Math.abs(candidateIdentifier - identifierToRoute);\r
+                distance = Math.min(distance, 1.0 - distance);\r
+\r
+                // if clockwise i have to exclude the case: candidateIdentifier - indentifierToRoute - identifier\r
+                if (currentClockwise) {\r
+                    if (isLeftNeighbour(candidateIdentifier, identifierToRoute)) {\r
+\r
+                        // Special case (0.9 - 0.1) the normal order is not more meanful to decide the side\r
+                        if (identifierToRoute >= candidateIdentifier) {\r
+                            distance = identifierToRoute - candidateIdentifier;\r
+                        } else {\r
+                            distance = (1.0 - candidateIdentifier) + identifierToRoute;\r
+                        }\r
+                    } else {\r
+                        distance = (1.0 - (candidateIdentifier - identifierToRoute)) % 1;\r
+                    }\r
+                }\r
+\r
+                /*\r
+                 *\r
+                 * Priority to the node that i'm directly connected and only after i use the\r
+                 * lookAhead information\r
+                 */\r
+                if (min >= Math.abs(distance)\r
+                        && (candidateIdentifier.equals(realCandidateIdentifier)\r
+                        || ret == null\r
+                        || min > Math.abs(distance))) {\r
+                    ret = node;\r
+                    min = Math.abs(distance);\r
+                }\r
+            }\r
+        }\r
+\r
+        if (ret == null) {\r
+            throw new RoutingException("Impossible do routing. [Hit: Neighbour links (maybe) not yet online.");\r
+        }\r
+\r
+        return ret;\r
+    }\r
+\r
+    /**\r
+     *\r
+     * @param neighbourNode Neighbour Node\r
+     * @return true if the node is a left neighbour (or itself), false if it is a right one\r
+     */\r
+    public static boolean isLeftNeighbour(Node rootNode, Node neighbourNode) {\r
+        SymphonyProtocol rootSymphony = (SymphonyProtocol) rootNode.getProtocol(pid);\r
+        SymphonyProtocol neighbourSymphony = (SymphonyProtocol) neighbourNode.getProtocol(pid);\r
+\r
+        return isLeftNeighbour(rootSymphony.getIdentifier(), neighbourSymphony.getIdentifier());\r
+    }\r
+\r
+    public static boolean isLeftNeighbour(double rootIdentifier, double neighbourIdentifier) {\r
+\r
+        // I calculate putting the hypotesis that i have to translate/"normalize", after i'll check if it was useless\r
+        double traslateRootIdentifier = (rootIdentifier + 0.5) % 1;\r
+        double traslateNeighbourIdentifier = (neighbourIdentifier + 0.5) % 1;\r
+        double distance = traslateNeighbourIdentifier - traslateRootIdentifier;\r
+\r
+        // I verify if the neighbourIdentifier is over half ring, if yes i don't need to do the translation/"normalization"\r
+        if ((neighbourIdentifier + 0.5) != traslateNeighbourIdentifier) {\r
+            distance = neighbourIdentifier - rootIdentifier;\r
+        }\r
+\r
+        return distance >= 0 && distance <= 0.5;\r
+    }\r
+\r
+    public void route(Node src, double key, Handler handler) throws RoutingException {\r
+\r
+        mapHandler.put(key, handler);\r
+\r
+        Message msg = new Message(key, src, MessageType.ROUTE);\r
+\r
+        Node targetNode = src;\r
+\r
+        if (!isManagerOf(key)) {\r
+            targetNode = getCandidateForRouting(key);\r
+            Transport transport = (Transport) src.getProtocol(transportID);\r
+            transport.send(src, targetNode, msg, pid);\r
+        }\r
+\r
+        // Insert the message into the chronology\r
+        Tuple<Message, Message> historyTuple = new Tuple<Message, Message>();\r
+        try {\r
+            historyTuple.x = msg;\r
+            historyTuple.y = (Message) msg.clone();\r
+            historyTuple.y.setCurrentHop(targetNode);\r
+        } catch (CloneNotSupportedException ex) {\r
+            Logger.getLogger(SymphonyProtocol.class.getName()).log(Level.SEVERE, "Impossible to clonate the message!");\r
+            historyTuple.x = null;\r
+            historyTuple.y = msg;\r
+            msg.setCurrentHop(targetNode);\r
+        }\r
+        messageHistory.add(new SoftReference<Tuple<Message, Message>>(historyTuple));\r
+        messageHistoryID.add(msg.getID());\r
+\r
+        /*\r
+         *\r
+         * If i am the manager (brutally through the reference), i don't do the loopback routing but\r
+         * i soddisfy immediately the request\r
+         */\r
+        if (targetNode == src) {\r
+\r
+            // Uppdate the chronology\r
+            historyTuple.y = new Message(key, targetNode, MessageType.ROUTE_RESPONSE);\r
+\r
+            Tuple<Node, Double> tuple = new Tuple<Node, Double>(src, key);\r
+            mapHandler.remove(key);\r
+            handler.handle(this, tuple);\r
+        }\r
+    }\r
+\r
+    public void processEvent(Node node, int pid, Object event) {\r
+        Message msg = (Message) event;\r
+        msg.incrementHop(); // I increment the message Hop\r
+\r
+        Tuple<Message, Message> historyTuple = new Tuple<Message, Message>();\r
+        try {\r
+            // I clone the message such a way to store into the chronology the hop sender's information\r
+            historyTuple.x = (Message) msg.clone();\r
+        } catch (CloneNotSupportedException ex) {\r
+            Logger.getLogger(SymphonyProtocol.class.getName()).log(Level.SEVERE, "Impossible to clonate the message!");\r
+            historyTuple.x = msg;\r
+        }\r
+\r
+        messageHistory.add(new SoftReference<Tuple<Message, Message>>(historyTuple));\r
+\r
+        Double key;\r
+        Transport transport;\r
+        Handler handler;\r
+\r
+        // Individuate cycles\r
+        if (messageHistoryID.contains(msg.getID())) {\r
+            Message responseMsg = new Message(msg, node, MessageType.ROUTE_FAIL);\r
+\r
+            historyTuple.y = responseMsg;\r
+\r
+            transport = (Transport) node.getProtocol(transportID);\r
+            transport.send(node, msg.getSourceNode(), responseMsg, pid);\r
+            return;\r
+        }\r
+\r
+        /*\r
+         * If i'm arrived till here means that i'm not into a cycle --> i insert the message ID into\r
+         * the chronology\r
+         */\r
+        messageHistoryID.add(msg.getID());\r
+\r
+        switch (msg.getType()) {\r
+            case ROUTE:\r
+                key = (Double) msg.getBody();\r
+                Logger.getLogger(SymphonyProtocol.class.getName()).log(Level.FINEST, key + " " + identifier);\r
+                if (isManagerOf(key)) {\r
+                    transport = (Transport) msg.getSourceNode().getProtocol(transportID);\r
+                    Message responseMsg = new Message(new Tuple<Node, Double>(node, key), node, MessageType.ROUTE_RESPONSE);\r
+                    historyTuple.y = responseMsg;\r
+                    transport.send(node, msg.getSourceNode(), responseMsg, pid);\r
+                } else {\r
+                    try {\r
+                        Node targetNode = getCandidateForRouting(key);\r
+\r
+                        try {\r
+                            // I clone the message such a way to store the info (into the chronology) of the hop receiver\r
+                            historyTuple.y = (Message) msg.clone();\r
+                            historyTuple.y.setCurrentHop(targetNode);\r
+                        } catch (CloneNotSupportedException ex) {\r
+                            Logger.getLogger(SymphonyProtocol.class.getName()).log(Level.SEVERE, "Impossible to clonate the message!");\r
+                            historyTuple.y = msg;\r
+                            msg.setCurrentHop(targetNode);\r
+                        }\r
+\r
+                        transport = (Transport) node.getProtocol(transportID);\r
+                        transport.send(node, targetNode, msg, pid);\r
+                    } catch (RoutingException ex) {\r
+                        /*\r
+                         *\r
+                         * I send the same message to myself (it is going to queue into the event\r
+                         * queue and in this way i "earn" time (postpone) and i hope that the\r
+                         * network will be ok in the meanwhile)\r
+                         */\r
+                        historyTuple.y = msg;\r
+                        msg.setCurrentHop(node);\r
+                        transport = (Transport) node.getProtocol(transportID);\r
+                        transport.send(node, node, msg, pid);\r
+                    }\r
+                }\r
+                break;\r
+            case ROUTE_RESPONSE:\r
+                Tuple<Node, Double> tuple = (Tuple<Node, Double>) msg.getBody();\r
+                key = tuple.y;\r
+                handler = mapHandler.get(key);\r
+                mapHandler.remove(key);\r
+                handler.handle(this, tuple);\r
+                break;\r
+            case ROUTE_FAIL:\r
+                Message requestMsg = (Message) msg.getBody();\r
+                key = (Double) requestMsg.getBody();\r
+                handler = mapHandler.get(key);\r
+                mapHandler.remove(key);\r
+                handler.handle(this, null);\r
+                break;\r
+        }\r
+    }\r
+\r
+    public boolean isManagerOf(double key) {\r
+\r
+        if (key == identifier) {\r
+            return true;\r
+        }\r
+\r
+        SymphonyNodeComparator comparator = new SymphonyNodeComparator(pid, identifier);\r
+        AdapterSymphonyNodeComparator adapterComparator = new AdapterSymphonyNodeComparator(comparator);\r
+\r
+        Collection<Tuple<Node, BootstrapStatus>> leftShortRangeLinksCloned = (Collection<Tuple<Node, BootstrapStatus>>) leftShortRangeLinks.clone();\r
+        Node targetNode = null;\r
+\r
+        while (targetNode == null && !leftShortRangeLinksCloned.isEmpty()) {\r
+            Tuple<Node, BootstrapStatus> nearTuple = Collections.min(leftShortRangeLinksCloned, adapterComparator);\r
+            if (nearTuple.y == BootstrapStatus.ONLINE) {\r
+                targetNode = nearTuple.x;\r
+            } else {\r
+                leftShortRangeLinksCloned.remove(nearTuple);\r
+            }\r
+        }\r
+\r
+        // SPECIAL CASE: NO LEFT NEIGHBOURS. I became the Manager.\r
+        if (targetNode == null) {\r
+            return true;\r
+        }\r
+\r
+        SymphonyProtocol symphony = (SymphonyProtocol) targetNode.getProtocol(pid);\r
+        // Check if it's the situation: right neighbour - key - me. So if i'm the manager or not.\r
+        boolean ret = isLeftNeighbour(identifier, key) && (!isLeftNeighbour(symphony.getIdentifier(), key) && symphony.getIdentifier() != key);\r
+\r
+        return ret;\r
+    }\r
+\r
+    public double getIdentifier() {\r
+        return identifier;\r
+    }\r
+\r
+    public Tuple<Message, Message>[] getHistoryMessage() {\r
+        SoftReference<Tuple<Message, Message>>[] array = messageHistory.toArray(new SoftReference[0]);\r
+        LinkedList<Tuple<Message, Message>> list = new LinkedList<Tuple<Message, Message>>();\r
+        for (SoftReference<Tuple<Message, Message>> reference : array) {\r
+            Tuple<Message, Message> tuple = reference.get();\r
+            if (tuple != null) {\r
+                list.add(tuple);\r
+            }\r
+        }\r
+        return list.toArray(new Tuple[0]);\r
+    }\r
+\r
+    public void clearHistoryMessage() {\r
+        messageHistory.clear();\r
+    }\r
+\r
+    private double generateUniqueIdentifier() {\r
+        boolean duplicated = true;\r
+        Double id = null;\r
+\r
+        while (duplicated) {\r
+            id = CommonState.r.nextDouble();\r
+            duplicated = allIdentifier.contains(id);\r
+        }\r
+\r
+        allIdentifier.add(id);\r
+\r
+        return id;\r
+    }\r
+\r
+    @Override\r
+    public Object clone() {\r
+        SymphonyProtocol dolly = new SymphonyProtocol(prefix);\r
+        return dolly;\r
+    }\r
+\r
+    public boolean isBootstrapped() {\r
+        return loggedIntoNetwork == BootstrapStatus.ONLINE;\r
+    }\r
+}\r
diff --git a/contrib/psg/src/example/symphony/SymphonyStatistics.java b/contrib/psg/src/example/symphony/SymphonyStatistics.java
new file mode 100644 (file)
index 0000000..4e97219
--- /dev/null
@@ -0,0 +1,77 @@
+package example.symphony;\r
+\r
+import peersim.config.Configuration;\r
+import peersim.core.Control;\r
+import peersim.core.Network;\r
+import peersim.core.Node;\r
+\r
+/**\r
+ *\r
+ * @author Andrea Esposito <and1989@gmail.com>\r
+ */\r
+public class SymphonyStatistics implements Control {\r
+\r
+    private static final String PAR_SYMPHONY = "symphony";\r
+    private final int symphonyID;\r
+    private long totalMsg = 0;\r
+    private long numRouteResposeMsg = 0;\r
+    private long numRouteMsg = 0;\r
+    private long numRouteFailMsg = 0;\r
+    private long numRouteFoundManagerMsg = 0;\r
+    private double mediaHopRouteResponseMsg = 0.0;\r
+\r
+    public SymphonyStatistics(String prefix) {\r
+        symphonyID = Configuration.getPid(prefix + "." + PAR_SYMPHONY);\r
+    }\r
+\r
+    public boolean execute() {\r
+\r
+        AdapterIterableNetwork itNetwork = new AdapterIterableNetwork();\r
+        for (Node node : itNetwork) {\r
+            SymphonyProtocol symphony = (SymphonyProtocol) node.getProtocol(symphonyID);\r
+            Tuple<Message, Message>[] tupleMessages = symphony.getHistoryMessage();\r
+            totalMsg += tupleMessages.length;\r
+\r
+            for (Tuple<Message, Message> tupleMessage : tupleMessages) {\r
+\r
+                Message message = tupleMessage.x;\r
+\r
+                if (message != null) {\r
+                    switch (message.getType()) {\r
+                        case ROUTE:\r
+                            numRouteMsg++;\r
+                            if (tupleMessage.y != null && tupleMessage.y.getType() == Message.MessageType.ROUTE_RESPONSE) {\r
+                                numRouteFoundManagerMsg++;\r
+                                mediaHopRouteResponseMsg = ((mediaHopRouteResponseMsg * (numRouteFoundManagerMsg - 1)) + message.getHop()) / (double) numRouteFoundManagerMsg;\r
+                            }\r
+                            break;\r
+                        case ROUTE_FAIL:\r
+                            numRouteFailMsg++;\r
+                            break;\r
+                        case ROUTE_RESPONSE:\r
+                            numRouteResposeMsg++;\r
+                            break;\r
+                    }\r
+                }\r
+            }\r
+\r
+            symphony.clearHistoryMessage();\r
+        }\r
+\r
+        printStatistics();\r
+\r
+        return false;\r
+    }\r
+\r
+    private void printStatistics() {\r
+        System.out.println("### Statistics ###");\r
+        System.out.println("- Total Messages: " + totalMsg);\r
+        System.out.println("- Total Route Messages: " + numRouteMsg);\r
+        System.out.println("- Found Manager Route Message: " + numRouteFoundManagerMsg);\r
+        System.out.println("- Response Message: " + numRouteResposeMsg);\r
+        System.out.println("- Fail Message: " + numRouteFailMsg);\r
+        System.out.println();\r
+        System.out.println("Average Hop:" + mediaHopRouteResponseMsg + " Expected value (k = log n): " + (Math.log(Network.size()) / Math.log(2)));\r
+        System.out.println("### END ###\n");\r
+    }\r
+}\r
diff --git a/contrib/psg/src/example/symphony/Tuple.java b/contrib/psg/src/example/symphony/Tuple.java
new file mode 100644 (file)
index 0000000..ed82b64
--- /dev/null
@@ -0,0 +1,45 @@
+package example.symphony;\r
+\r
+/**\r
+ *\r
+ * @author Andrea Esposito <and1989@gmail.com>\r
+ */\r
+public class Tuple<X, Y> {\r
+\r
+    public X x;\r
+    public Y y;\r
+\r
+    public Tuple() {\r
+    }\r
+\r
+    public Tuple(X x, Y y) {\r
+        this.x = x;\r
+        this.y = y;\r
+    }\r
+\r
+    @Override\r
+    public boolean equals(Object obj) {\r
+\r
+        if (obj instanceof Tuple) {\r
+            Tuple tuple = (Tuple) obj;\r
+\r
+            // (x != null && tuple.x != null) ==> (x==tuple.x || x.equals(tuple.x))\r
+            // x == null <==> tuple.x == null\r
+\r
+            boolean equalsX = (x == null && tuple.x == null) || ((x != null && tuple.x != null) && (x == tuple.x || x.equals(tuple.x)));\r
+            boolean equalsY = (y == null && tuple.y == null) || ((y != null && tuple.y != null) && (y == tuple.y || y.equals(tuple.y)));\r
+\r
+            return equalsX && equalsY;\r
+        }\r
+\r
+        return false;\r
+    }\r
+\r
+    @Override\r
+    public int hashCode() {\r
+        int hash = 5;\r
+        hash = 89 * hash + (this.x != null ? this.x.hashCode() : 0);\r
+        hash = 89 * hash + (this.y != null ? this.y.hashCode() : 0);\r
+        return hash;\r
+    }\r
+}\r
diff --git a/contrib/psg/src/example/symphony/test/NetworkEstimationTest.java b/contrib/psg/src/example/symphony/test/NetworkEstimationTest.java
new file mode 100644 (file)
index 0000000..1d0d945
--- /dev/null
@@ -0,0 +1,52 @@
+package example.symphony.test;\r
+\r
+import example.symphony.AdapterIterableNetwork;\r
+import example.symphony.SymphonyNetworkManager;\r
+import example.symphony.SymphonyProtocol;\r
+import peersim.config.Configuration;\r
+import peersim.core.Control;\r
+import peersim.core.Node;\r
+\r
+/**\r
+ *\r
+ * @author Andrea Esposito <and1989@gmail.com>\r
+ */\r
+public class NetworkEstimationTest implements Control {\r
+\r
+    private static final String PAR_NETMANAGER = "symphonynetworkmanager";\r
+    private static final String PAR_SYMPHONY = "symphony";\r
+    private final int symphonyID;\r
+    private final int networkManagerID;\r
+\r
+    public NetworkEstimationTest(String prefix) {\r
+\r
+        networkManagerID = Configuration.getPid(prefix + "." + PAR_NETMANAGER);\r
+        symphonyID = Configuration.getPid(prefix + "." + PAR_SYMPHONY);\r
+    }\r
+\r
+    public boolean execute() {\r
+\r
+        AdapterIterableNetwork it = new AdapterIterableNetwork();\r
+        int max = Integer.MIN_VALUE;\r
+        int min = Integer.MAX_VALUE;\r
+        int sum = 0;\r
+        int total = 0;\r
+        for (Node node : it) {\r
+            if (node.isUp() && ((SymphonyProtocol) node.getProtocol(symphonyID)).isBootstrapped()) {\r
+                SymphonyNetworkManager networkManager = (SymphonyNetworkManager) node.getProtocol(networkManagerID);\r
+                int n = networkManager.getN();\r
+                min = n < min ? n : min;\r
+                max = n > max ? n : max;\r
+                sum += n;\r
+                total++;\r
+            }\r
+        }\r
+\r
+        System.out.println("Real Dimension: " + (Math.log(total) / Math.log(2)));\r
+        System.out.println("Average Estimated Dimension: " + (total == 0 ? "No Node online" : (Math.log((sum / total)) / Math.log(2))));\r
+        System.out.println("MAX: " + Math.log(max) / Math.log(2));\r
+        System.out.println("MIN: " + Math.log(min) / Math.log(2));\r
+\r
+        return false;\r
+    }\r
+}\r
diff --git a/contrib/psg/src/peersim/Simulator.java b/contrib/psg/src/peersim/Simulator.java
new file mode 100644 (file)
index 0000000..97c7965
--- /dev/null
@@ -0,0 +1,270 @@
+/*
+ * 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;
+
+import psgsim.PSGSimulator;
+
+import java.io.*;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+import org.simgrid.msg.HostNotFoundException;
+import org.simgrid.msg.NativeException;
+
+import peersim.cdsim.*;
+import peersim.config.*;
+import peersim.core.*;
+import peersim.edsim.*;
+
+/**
+ * This is the main entry point to peersim. This class loads configuration and
+ * detects the simulation type. According to this, it invokes the appropriate
+ * simulator. The known simulators at this moment, along with the way to detect
+ * them are the following:
+ * <ul>
+ * <li>{@link CDSimulator}: if {@link CDSimulator#isConfigurationCycleDriven}
+ * returns true</li>
+ * <li>{@link EDSimulator}: if {@link EDSimulator#isConfigurationEventDriven}
+ * returns true</li>
+ * </ul>
+ * 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.
+ * 
+ * @see #main
+ */
+public class Simulator {
+
+       // ========================== static constants ==========================
+       // ======================================================================
+       public static int nbreR = 0;
+       /** {@link CDSimulator} */
+       public static final int CDSIM = 0;
+
+       /** {@link EDSimulator} */
+       public static final int EDSIM = 1;
+
+       /** {@link psgsim.PSGSimulator} */
+       public static final int PSGSIM = 2;
+
+       /** Unknown simulator */
+       public static final int UNKNOWN = -1;
+
+       /** the class names of simulators used */
+       protected static final String[] simName = { "peersim.cdsim.CDSimulator",
+                       "peersim.edsim.EDSimulator", "psgsim.PSGSimulator" };
+
+       /**
+        * Parameter representing the number of times the experiment is run.
+        * Defaults to 1.
+        * 
+        * @config
+        */
+       public static final String PAR_EXPS = "simulation.experiments";
+
+       /**
+        * If present, this parameter activates the redirection of the standard
+        * output to a given PrintStream. This comes useful for processing the
+        * output of the simulation from within the simulator.
+        * 
+        * @config
+        */
+       public static final String PAR_REDIRECT = "simulation.stdout";
+
+       // ==================== static fields ===================================
+       // ======================================================================
+
+       /** */
+       private static int simID = UNKNOWN;
+
+       // ========================== methods ===================================
+       // ======================================================================
+
+       /**
+        * Returns the numeric id of the simulator to invoke. At the moment this can
+        * be {@link #CDSIM}, {@link #EDSIM} or {@link #UNKNOWN}.
+        */
+       public static int getSimID() {
+
+               if (simID == UNKNOWN) {
+                       if (CDSimulator.isConfigurationCycleDriven()) {
+                               simID = CDSIM;
+                       } else if (EDSimulator.isConfigurationEventDriven()) {
+                               simID = EDSIM;
+                       } else
+                               simID = PSGSIM;
+
+               }
+               return simID;
+       }
+
+       // ----------------------------------------------------------------------
+
+       /**
+        * Loads the configuration and executes the experiments. The number of
+        * independent experiments is given by config parameter {@value #PAR_EXPS}.
+        * In all experiments the configuration is the same, only the random seed is
+        * not re-initialized between experiments.
+        * <p>
+        * 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
+        * <code>args</code> is simply passed to this class. This class is then used
+        * to initialize the configuration.
+        * <p>
+        * After loading the configuration, the experiments are run by invoking the
+        * appropriate engine, which is identified as follows:
+        * <ul>
+        * <li>{@link CDSimulator}: if
+        * {@link CDSimulator#isConfigurationCycleDriven} returns true</li>
+        * <li>{@link EDSimulator}: if
+        * {@link EDSimulator#isConfigurationEventDriven} returns true</li>
+        * </ul>
+        * <p>
+        * 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 (file)
index 0000000..c0d2f0d
--- /dev/null
@@ -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 (file)
index 0000000..f487594
--- /dev/null
@@ -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.
+ * <p>
+ * 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}.
+ * <p>
+ * 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.
+ * <p>
+ * 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 (file)
index 0000000..ef52f78
--- /dev/null
@@ -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 (file)
index 0000000..73f9a4e
--- /dev/null
@@ -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<names.length; ++i)
+       {
+               controls[i]=(Control)Configuration.getInstance(names[i]);
+       }
+       System.err.println(s+": loaded controls "+Arrays.asList(names));
+}
+
+// ------------------------------------------------------------------
+
+public Object clone() {
+
+       DaemonProtocol ip = null;
+       try { ip=(DaemonProtocol)super.clone(); }
+       catch( CloneNotSupportedException e ) {} // never happens
+       return ip;
+}
+
+
+// ========================= methods =================================
+// ===================================================================
+
+       
+/**
+* Runs the configured controls if {@link CDState#getCycleT} %
+* {@value #PAR_STEP}=0.
+*/
+public void nextCycle( Node node, int protocolID ) {
+
+       if( CDState.getCycleT() % step != 0 ) return;
+       for(int j=0; j<controls.length; ++j) controls[j].execute();
+}
+
+}
+
diff --git a/contrib/psg/src/peersim/cdsim/FullNextCycle.java b/contrib/psg/src/peersim/cdsim/FullNextCycle.java
new file mode 100644 (file)
index 0000000..0bc97f4
--- /dev/null
@@ -0,0 +1,137 @@
+/*
+ * 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.config.*;
+import peersim.core.*;
+import peersim.util.RandPermutation;
+
+/**
+* Control to run a cycle of the cycle driven simulation.
+* This does not need to be explicitly configured (although you can do it for
+* hacking purposes).
+*/
+public class FullNextCycle implements Control {
+
+
+// ============== fields ===============================================
+// =====================================================================
+
+
+/**
+* The type of the getPair function. This parameter is of historic interest and
+* was needed in a publication we wrote. You don't need to care about this.
+* But if you wanna know: if set to "rand", then in a cycle the simulator
+* does not simply iterate through the nodes, but instead picks a random one
+* N times, where N is the network size.
+* @config
+*/
+private static final String PAR_GETPAIR = "getpair";
+
+/**
+* Shuffle iteration order if set. Not set by default. If set, then nodes are
+* iterated in a random order. However, in the network the nodes actually
+* stay in the order they originally were. The price for leaving the
+* network untouched is memory: we need to store the permutation we use
+* to iterate the network.
+* @config
+*/
+private static final String PAR_SHUFFLE = "shuffle";
+
+// --------------------------------------------------------------------
+
+protected final boolean getpair_rand;
+
+protected final boolean shuffle;
+
+/** Holds the protocol schedulers of this simulation */
+protected Scheduler[] protSchedules = null;
+
+/** The random permutation to use if config par {@value #PAR_SHUFFLE} is set. */
+protected RandPermutation rperm = new RandPermutation( CDState.r );
+
+// =============== initialization ======================================
+// =====================================================================
+
+/**
+* Reads config parameters and {@link Scheduler}s.
+*/
+public FullNextCycle(String prefix) {
+       
+       getpair_rand = Configuration.contains(prefix+"."+PAR_GETPAIR);
+       shuffle = Configuration.contains(prefix+"."+PAR_SHUFFLE);
+
+       // load protocol schedulers
+       String[] names = Configuration.getNames(Node.PAR_PROT);
+       protSchedules = new Scheduler[names.length];
+       for(int i=0; i<names.length; ++i)
+       {
+               protSchedules[i] = new Scheduler(names[i]);
+       }
+}
+
+// =============== methods =============================================
+// =====================================================================
+
+/** 
+ * Execute all the {@link CDProtocol}s on all nodes that are up.
+ * If the node goes down as a result of the execution of a protocol, then
+ * the rest of the protocols on that node are not executed and we move on
+ * to the next node.
+ * It sets the {@link CDState} appropriately.
+ * @return always false
+ */
+public boolean execute() {
+
+       final int cycle=CDState.getCycle();
+       if( shuffle ) rperm.reset( Network.size() );
+       for(int j=0; j<Network.size(); ++j)
+       {
+               Node node = null;
+               if( getpair_rand )
+                       node = Network.get(CDState.r.nextInt(Network.size()));
+               else if( shuffle )
+                       node = Network.get(rperm.next());
+               else
+                       node = Network.get(j);
+               if( !node.isUp() ) continue; 
+               CDState.setNode(node);
+               CDState.setCycleT(j);
+               final int len = node.protocolSize();
+               for(int k=0; k<len; ++k)
+               {
+                       // Check if the protocol should be executed, given the
+                       // associated scheduler.
+                       if (!protSchedules[k].active(cycle))
+                               continue;
+                               
+                       CDState.setPid(k);
+                       Protocol protocol = node.getProtocol(k);
+                       if( protocol instanceof CDProtocol )
+                       {
+                               ((CDProtocol)protocol).nextCycle(node, k);
+                               if( !node.isUp() ) break;
+                       }
+               }
+       }
+
+       return false;
+}
+
+}
diff --git a/contrib/psg/src/peersim/cdsim/NextCycle.java b/contrib/psg/src/peersim/cdsim/NextCycle.java
new file mode 100644 (file)
index 0000000..464f398
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+ * 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.config.*;
+import peersim.core.*;
+
+/**
+* It generalizes its superclass so that the list of protocols to run can
+* be specified. The superclass ({@link FullNextCycle}) always runs all the
+* {@link CDProtocol}s.
+*/
+public class NextCycle extends FullNextCycle {
+
+
+// ============== fields ===============================================
+// =====================================================================
+
+
+/**
+* Gives the list of protocols (whitespace separated) that need to be
+* iterated over.
+* @config
+*/
+private static final String PAR_PROTS = "protocol";
+
+private final int[] pids;
+
+
+// =============== initialization ======================================
+// =====================================================================
+
+/**
+* reads configuration parameters and the {@link Scheduler}s.
+*/
+public NextCycle(String prefix) {
+       
+       super(prefix);
+       
+       String prots = Configuration.getString(prefix+"."+PAR_PROTS);
+       String[] protnames = prots.split("\\s");
+       pids = new int[protnames.length];
+       for(int i=0; i<protnames.length; ++i)
+       {
+               pids[i] = Configuration.lookupPid(protnames[i]);
+       }
+}
+
+// =============== methods =============================================
+// =====================================================================
+
+/** 
+ * Execute the configured protocols on all nodes.
+ * It works exactly as {@link FullNextCycle#execute}, only just the configured
+ * protocols are iterated over.
+ */
+public boolean execute() {
+
+       final int cycle=CDState.getCycle();
+       if( shuffle ) rperm.reset( Network.size() );
+       for(int j=0; j<Network.size(); ++j)
+       {
+               Node node = null;
+               if( getpair_rand )
+                       node = Network.get(CDState.r.nextInt(Network.size()));
+               else if( shuffle )
+                       node = Network.get(rperm.next());
+               else
+                       node = Network.get(j);
+               if( !node.isUp() ) continue; 
+               CDState.setNode(node);
+               CDState.setCycleT(j);
+               for(int pid: pids)
+               {
+                       // Check if the protocol should be executed, given the
+                       // associated scheduler.
+                       if (!protSchedules[pid].active(cycle))
+                               continue;
+                               
+                       CDState.setPid(pid);
+                       Protocol protocol = node.getProtocol(pid);
+                       if( protocol instanceof CDProtocol )
+                       {
+                               ((CDProtocol)protocol).nextCycle(node, pid);
+                               if( !node.isUp() ) break;
+                       }
+               }
+       }
+
+       return false;
+}
+
+}
+
+
diff --git a/contrib/psg/src/peersim/cdsim/Shuffle.java b/contrib/psg/src/peersim/cdsim/Shuffle.java
new file mode 100644 (file)
index 0000000..6373940
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * 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.*;
+
+/**
+* Shuffles the network. After shuffling, the order in which the nodes
+* are iterated over during a cycle of a cycle driven simulation
+* will be random. It has an effect only in cycle driven simulations.
+*/
+public class Shuffle implements Control {
+
+
+// ========================= fields =================================
+// ==================================================================
+
+// ==================== initialization ==============================
+// ==================================================================
+
+/** Does nothing. */
+public Shuffle(String prefix) {}
+
+
+// ===================== public methods ==============================
+// ===================================================================
+
+
+/**
+* Calls {@link Network#shuffle()}. 
+* As a result, the order in which the nodes
+* are iterated over during a cycle of a cycle driven simulation
+* will be random. It has an effect only in cycle driven simulations.
+*/
+public final boolean execute() {
+       Network.shuffle();
+       return false;
+}
+
+
+}
+
+
diff --git a/contrib/psg/src/peersim/config/CheckConfig.java b/contrib/psg/src/peersim/config/CheckConfig.java
new file mode 100644 (file)
index 0000000..117dcc0
--- /dev/null
@@ -0,0 +1,186 @@
+/*
+ * 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.*;
+
+import peersim.cdsim.*;
+import peersim.edsim.*;
+import peersim.util.*;
+
+
+/**
+ * This is utility tool that checks whether a config file can be loaded
+ * or not, without actually performing the simulation. All the error
+ * messages generated by controls and protocols when initialized are
+ * reported.  This is useful to check all the configuration files in a 
+ * directory.
+ */
+public class CheckConfig {
+
+//========================== parameters ================================
+//======================================================================
+
+/**
+ * This is the prefix of the config properties whose value vary during
+ * a set of experiments.
+ * @config
+ */
+private static final String PAR_RANGE = "range";
+
+
+// ========================== static constants ==========================
+// ======================================================================
+
+/** {@link CDSimulator} */
+protected static final int CDSIM = 0;
+
+/** {@link EDSimulator} */
+protected static final int EDSIM = 1;
+
+protected static final int UNKNOWN = -1;
+
+/** the class names of simulators used */
+protected static final String[] simName = {
+       CDSimulator.class.getCanonicalName(),
+       EDSimulator.class.getCanonicalName(),
+};
+
+
+
+       
+// ========================== methods ===================================
+// ======================================================================
+
+/**
+* Returns the numeric id of the simulator to invoke. At the moment this can
+* be {@link #CDSIM}, {@link #EDSIM} or {@link #UNKNOWN}.
+*/
+protected static int getSimID() {
+       
+       if( CDSimulator.isConfigurationCycleDriven())
+       {
+               return CDSIM;
+       }
+       else if( EDSimulator.isConfigurationEventDriven() )
+       {       
+               return EDSIM;
+       }
+       else    return UNKNOWN;
+}
+
+// ----------------------------------------------------------------------
+
+/**
+* Loads the configuration and checks the configuration files against
+* simple configuration errors, such as missing classes, missing 
+* parameters or syntax errors.
+* <p>
+* The goal is to provide a mechanism to test a configuration file,
+* without having to perform the actual simulations (that could be
+* time-consuming) and without necessarily blocking after the first
+* error encountered. It may be useful, for example, when a major 
+* refactoring of your code requires a thorough check on all your 
+* configuration files.
+* <p>
+* 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.
+* <p>
+* 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. 
+* <p>
+* 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 <parameter>;<value list>");
+               }
+               String[] values = StringListParser.parseList(array[1]);
+               prop.setProperty(array[0], values[0]);
+       }
+}
+
+}
diff --git a/contrib/psg/src/peersim/config/ClassFinder.java b/contrib/psg/src/peersim/config/ClassFinder.java
new file mode 100644 (file)
index 0000000..b7cab6b
--- /dev/null
@@ -0,0 +1,258 @@
+/*
+ * 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.*;
+import java.util.zip.*;
+
+/**
+ * Provides static methods to obtain the package-qualified class name
+ * of a class, given just the non-qualified name, and to obtain
+ * the non-qualified name, given the package-qualified class name.
+ * 
+ * Inspired from some code written by David Postill (david@postill.org.uk)
+ * (found in http://groups.google.com).
+ *
+ *
+ * @author Alberto Montresor
+ * @version $Revision: 1.9 $
+ */
+class ClassFinder 
+{
+
+//--------------------------------------------------------------------------
+//Fields and initialization
+//--------------------------------------------------------------------------
+       
+       
+/** Local map containing the associations */
+private static Map<String,String> map = new TreeMap<String,String>();  
+
+/** The number of directories that have been touched by the search.
+This does not include directories in jar files. */
+private static int visitedDirs = 0;
+
+private static final int maxDirs;
+
+static {
+
+       maxDirs = 10000;
+
+       try {
+               findClasses(map);
+       } catch (IOException e) {
+               e.printStackTrace();
+       }
+
+       if(visitedDirs >= maxDirs )
+       {
+               System.err.println("Configuration: some directories in your "+
+               "classpath probably contain filesystem\nConfiguration: "+
+               "loops because the number of visited directories "+
+               "reached "+maxDirs+".\nConfiguration: This means automatic "+
+               "class lookup might fail and you might have\nConfiguration: "+
+               "to fully qualify class names in the configuration.");
+       }
+}
+       
+       
+//--------------------------------------------------------------------------
+//Public static methods
+//--------------------------------------------------------------------------
+       
+/**
+ * Returns the non-qualified name of a class, removing all the package
+ * information.
+ */
+public static String getShortName(String className) {
+
+       int index = className.lastIndexOf('.');
+       if (index < 0) {
+               return className;
+       } else {
+               return className.substring(index+1);
+       }
+}
+
+/**
+ * Returns the package-qualified name associated to the specified
+ * non-qualified name, if exists. Otherwise it returns null.
+ * 
+ * Only classes reachable from the classpath defined by the 
+ * "java.class.path" property are considered. 
+ * Jar files and directories are both parsed.
+ * If multiple classes with the same name but different 
+ * fully-qualified names are present, a comma-separated list
+ * of fully-qualified class names is returned.
+ * 
+ * @param name the non-qualified name of the class to be searched
+ * @return the qualified name, if exists.
+ */
+public static String getQualifiedName(String name)
+{
+       return map.get(name);
+}
+
+//--------------------------------------------------------------------------
+//Private static methods
+//--------------------------------------------------------------------------
+       
+/**
+ * Finds all the classes reachable from the current classpath;
+ * for each of them, inserts an association (name, fully-qualified 
+ * name) in the specified map. Both names are String objects.
+ * 
+ * Only classes reachable from the classpath defined by the 
+ * "java.class.path" property are considered. 
+ * Jar files and directories are both parsed.
+ * If multiple classes with the same name but different 
+ * fully-qualified names are present, they are inserted
+ * in the map as associations (name, comma-separated list of
+ * fully-qualified names).
+ * 
+ * @param map
+ * @throws IOException
+ */
+private static void findClasses(Map<String,String> map)
+throws IOException
+{
+       String classPath = System.getProperty( "java.class.path" );
+       String separator = System.getProperty( "path.separator"  );
+       String filesep = System.getProperty( "file.separator");
+       StringTokenizer path = new StringTokenizer( classPath, separator );
+
+       while( path.hasMoreTokens() ) {
+               
+               String pathElement = path.nextToken();
+               File pathFile = new File( pathElement );
+               
+               if( pathFile.isDirectory() ) {
+                       if (!pathElement.endsWith(filesep)) {
+                               pathElement = pathElement + filesep;
+                               pathFile = new File( pathElement);
+                       }
+                       findClassInPathDir( map, pathElement, pathFile );
+                       // Search directories
+               } else if ( pathFile.exists() ) {
+                       findClassInJar( map, pathFile);
+               }
+       }
+}
+
+//--------------------------------------------------------------------------
+
+/**
+ * Parses jar file.
+ * 
+ * @param map the map where to insert associations
+ * @param pathFile the file name of the associated jar file
+ * @throws IOException
+ */
+private static void findClassInJar(Map<String,String> map, File pathFile)
+throws IOException
+{
+       ZipFile zipFile = new ZipFile( pathFile );
+       Enumeration entries = zipFile.entries();
+       while( entries.hasMoreElements() ) {
+               
+               String entry = entries.nextElement().toString();
+               if( entry.endsWith( ".class" ) ) {
+                       // File names in ZIP archives (so, also in JARs)
+                       // are separated by forward slashes '/', independently
+                       // of the architecture.
+                       String className = classname( entry, "/" ); 
+                       String shortName = getShortName( className );
+                       if (map.containsKey(shortName)) {
+                               map.put(shortName,
+                                       map.get(shortName)+","+className);
+                       } else {
+                               map.put(shortName, className);
+                       }
+               }
+       }
+}
+
+//--------------------------------------------------------------------------
+
+/**
+ * Recursively parses directories.
+ * 
+ * @param map the map where to insert associations
+ * @param pathElement the path string used for recursion
+ * @param pathFile the file (directory) to be analyzed
+ * @throws IOException
+ */
+private static void findClassInPathDir( Map<String,String> map,
+       String pathElement, File pathFile )
+throws IOException
+{
+       visitedDirs++;
+       if(visitedDirs>=maxDirs) return;
+
+       String[] list = pathFile.list();
+       String filesep = System.getProperty( "file.separator");
+       
+       for( int i = 0; i < list.length; i++ ) {
+               File file = new File( pathFile, list[i] );
+               if( file.isDirectory() ) {
+                       findClassInPathDir( map, pathElement, file );
+               }
+               else if ( file.exists() && (file.length() != 0) && list[i].endsWith( ".class" ) ) {
+                       String classFile = file.toString().substring( pathElement.length());
+                       String className = classname( classFile, filesep );
+                       String shortName = getShortName( className );
+                       if (map.containsKey(shortName)) {
+                               map.put(shortName, map.get(shortName)+","+className);
+                       } else {
+                               map.put(shortName, className);
+                       }
+               }
+       }
+}
+
+//--------------------------------------------------------------------------
+
+/**
+ * Translates a class file name in a class name using
+ * the specified file separator.
+ */
+private static String classname(String classFile, String filesep)
+{ 
+       return classFile.replace( filesep, "." ).substring(
+               0, classFile.length() - ".class".length() ); 
+}
+
+//--------------------------------------------------------------------------
+
+/** 
+ * Testing.
+ * 
+ * @param argv
+ */
+public static void main( String[] argv )
+{
+       Iterator i = map.keySet().iterator();
+       while (i.hasNext()) {
+               String key = (String) i.next();
+               String name = map.get(key);
+               System.out.println(key + " --> " + name);
+       }
+}
+}
diff --git a/contrib/psg/src/peersim/config/ConfigContainer.java b/contrib/psg/src/peersim/config/ConfigContainer.java
new file mode 100644 (file)
index 0000000..75f3cb6
--- /dev/null
@@ -0,0 +1,1011 @@
+/*
+ * 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.lang.reflect.*;
+import java.util.*;
+import org.lsmp.djep.groupJep.*;
+
+/**
+ * This class is the container for the configuration data used in
+ * {@link Configuration}; see that class for more information.
+ */
+public class ConfigContainer
+{
+
+// =================== static fields =================================
+// ===================================================================
+
+/** Symbolic constant for no debug */
+private static final int DEBUG_NO = 0;
+
+/** Symbolic constant for regular debug */
+private static final int DEBUG_REG = 1;
+
+/** Symbolic constant for extended debug */
+private static final int DEBUG_CONTEXT = 2;
+
+//========================== fields =================================
+//===================================================================
+
+/**
+ * The properties object that stores all configuration information.
+ */
+private Properties config;
+
+/**
+ * Map associating string protocol names to the numeric protocol
+ * identifiers. The protocol names are understood without prefix.
+ */
+private Map<String, Integer> protocols;
+
+/**
+ * The maximum depth that can be reached when analyzing expressions. This
+ * value can be substituted by setting the configuration parameter
+ * PAR_MAXDEPTH.
+ */
+private int maxdepth;
+
+/** Debug level */
+private int debugLevel;
+
+/**
+ * If true, no exception is thrown. Instead, an error is printed and the
+ * Configuration tries to return a reasonable return value
+ */
+private boolean check = false;
+
+// =================== initialization ================================
+// ===================================================================
+
+public ConfigContainer(Properties config, boolean check)
+{
+       this.config = config;
+       this.check = check;
+       maxdepth = getInt(Configuration.PAR_MAXDEPTH, Configuration.DEFAULT_MAXDEPTH);
+
+       // initialize protocol id-s
+       protocols = new HashMap<String, Integer>();
+       String[] prots = getNames(Configuration.PAR_PROT);// they're returned in correct order
+       for (int i = 0; i < prots.length; ++i) {
+               protocols.put(prots[i].substring(Configuration.PAR_PROT.length() + 1), Integer.valueOf(i));
+       }
+       String debug = config.getProperty(Configuration.PAR_DEBUG);
+       if (Configuration.DEBUG_EXTENDED.equals(debug))
+               debugLevel = DEBUG_CONTEXT;
+       else if (Configuration.DEBUG_FULL.equals(debug)) {
+               Map<String, String> map = new TreeMap<String, String>();
+               Enumeration e = config.propertyNames();
+               while (e.hasMoreElements()) {
+                       String name = (String) e.nextElement();
+                       String value = config.getProperty(name);
+                       map.put(name, value);
+               }
+               Iterator i = map.keySet().iterator();
+               while (i.hasNext()) {
+                       String name = (String) i.next();
+                       System.err.println("DEBUG " + name
+                                       + ("".equals(map.get(name)) ? "" : " = " + map.get(name)));
+               }
+       } else if (debug != null) {
+               debugLevel = DEBUG_REG;
+       } else {
+               debugLevel = DEBUG_NO;
+       }
+}
+
+// =================== static public methods =========================
+// ===================================================================
+
+/**
+ * @return true if and only if name is a specified (existing) property.
+ */
+public boolean contains(String name)
+{
+       boolean ret = config.containsKey(name);
+       debug(name, "" + ret);
+       return ret;
+}
+
+// -------------------------------------------------------------------
+
+/**
+ * Reads given configuration property. If not found, throws a
+ * {@link MissingParameterException}.
+ * @param name
+ *          Name of configuration property
+ * @param def
+ *          default value
+ */
+public boolean getBoolean(String name, boolean def)
+{
+       try {
+               return getBool(name);
+       } catch (RuntimeException e) {
+               manageDefault(name, def, e);
+               return 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 boolean getBoolean(String name)
+{
+       try {
+               return getBool(name);
+       } catch (RuntimeException e) {
+               manageException(name, e);
+               return false;
+       }
+}
+
+//-------------------------------------------------------------------
+
+/**
+ * The actual methods that implements getBoolean.
+ */
+private boolean getBool(String name)
+{
+       if (config.getProperty(name) == null) {
+               throw new MissingParameterException(name);
+//                             "\nPossibly incorrect property: " + getSimilarProperty(name));
+       }
+       if (config.getProperty(name).matches("\\p{Blank}*")) {
+               throw new MissingParameterException(name,
+                               "Blank value is not accepted when parsing Boolean.");
+       }
+       boolean ret = Boolean.valueOf(config.getProperty(name));
+       debug(name, "" + ret);
+       return ret;
+}
+
+// -------------------------------------------------------------------
+
+/**
+ * Reads given configuration property. If not found, returns the default
+ * value.
+ * @param name
+ *          Name of configuration property
+ * @param def
+ *          default value
+ */
+public int getInt(String name, int def)
+{
+       try {
+               Number ret = getVal(name, name, 0);
+               debug(name, "" + ret);
+               return ret.intValue();
+       } catch (RuntimeException e) {
+               manageDefault(name, def, e);
+               return def;
+       }
+}
+
+// -------------------------------------------------------------------
+
+/**
+ * Reads given configuration property. If not found, throws a
+ * {@link MissingParameterException}.
+ * @param name
+ *          Name of configuration property
+ */
+public int getInt(String name)
+{
+       try {
+               Number ret = getVal(name, name, 0);
+               debug(name, "" + ret);
+               return ret.intValue();
+       } catch (RuntimeException e) {
+               manageException(name, e);
+               return 0;
+       }
+}
+
+// -------------------------------------------------------------------
+
+/**
+ * Reads given configuration property. If not found, returns the default
+ * value.
+ * @param name
+ *          Name of configuration property
+ * @param def
+ *          default value
+ */
+public long getLong(String name, long def)
+{
+       try {
+               Number ret = getVal(name, name, 0);
+               debug(name, "" + ret);
+               return ret.longValue();
+       } catch (RuntimeException e) {
+               manageDefault(name, def, e);
+               return def;
+       }
+}
+
+// -------------------------------------------------------------------
+
+/**
+ * Reads given configuration property. If not found, throws a
+ * {@link MissingParameterException}.
+ * @param name
+ *          Name of configuration property
+ */
+public long getLong(String name)
+{
+       try {
+               Number ret = getVal(name, name, 0);
+               debug(name, "" + ret);
+               return ret.longValue();
+       } catch (RuntimeException e) {
+               manageException(name, e);
+                       return 0;
+       }
+}
+
+// -------------------------------------------------------------------
+
+/**
+ * Reads given configuration property. If not found, returns the default
+ * value.
+ * @param name
+ *          Name of configuration property
+ * @param def
+ *          default value
+ */
+public double getDouble(String name, double def)
+{
+       try {
+               Number ret = getVal(name, name, 0);
+               debug(name, "" + ret);
+               return ret.doubleValue();
+       } catch (RuntimeException e) {
+               manageDefault(name, def, e);
+               return def;
+       }
+}
+
+// -------------------------------------------------------------------
+
+/**
+ * Reads given configuration property. If not found, throws a
+ * MissingParameterException.
+ * @param name
+ *          Name of configuration property
+ */
+public double getDouble(String name)
+{
+       try {
+               Number ret = getVal(name, name, 0);
+               debug(name, "" + ret);
+               return ret.doubleValue();
+       } catch (RuntimeException e) {
+               manageException(name, e);
+               return 0;
+       }
+}
+
+// -------------------------------------------------------------------
+
+/**
+ * Read numeric property values, parsing expression if necessary.
+ * 
+ * @param initial
+ *          the property name that started this expression evaluation
+ * @param property
+ *          the current property name to be evaluated
+ * @param depth
+ *          the depth reached so far
+ * @return the evaluation of the expression associated to property
+ */
+private Number getVal(String initial, String property, int depth)
+{
+       if (depth > maxdepth) {
+               throw new IllegalParameterException(initial,
+                               "Probable recursive definition - exceeded maximum depth " + 
+                               maxdepth);
+       }
+
+       String s = config.getProperty(property);
+       if (s == null || s.equals("")) {
+               throw new MissingParameterException(property,
+                               " when evaluating property " + initial);
+//                                             + "\nPossibly incorrect property: " + getSimilarProperty(property));
+       }
+
+       GroupJep jep = new GroupJep(new Operators());
+       jep.setAllowUndeclared(true);
+
+       jep.parseExpression(s);
+       String[] symbols = getSymbols(jep);
+       for (int i = 0; i < symbols.length; i++) {
+               Object d = getVal(initial, symbols[i], depth + 1);
+               jep.addVariable(symbols[i], d);
+       }
+       Object ret = jep.getValueAsObject();
+       if (jep.hasError())
+               System.err.println(jep.getErrorInfo());
+       return (Number) ret;
+}
+
+// -------------------------------------------------------------------
+
+/**
+ * Returns an array of string, containing the symbols contained in the
+ * expression parsed by the specified JEP parser.
+ * @param jep
+ *          the java expression parser containing the list of variables
+ * @return an array of strings.
+ */
+private String[] getSymbols(org.nfunk.jep.JEP jep)
+{
+       Hashtable h = jep.getSymbolTable();
+       String[] ret = new String[h.size()];
+       Enumeration e = h.keys();
+       int i = 0;
+       while (e.hasMoreElements()) {
+               ret[i++] = (String) e.nextElement();
+       }
+       return ret;
+}
+
+// -------------------------------------------------------------------
+
+/**
+ * Reads given configuration property. If not found, returns the default
+ * value.
+ * @param name
+ *          Name of configuration property
+ * @param def
+ *          default value
+ */
+public String getString(String name, String def)
+{
+       try {
+               return getStr(name);
+       } catch (RuntimeException e) {
+               manageDefault(name, def, e);
+               return def;
+       } 
+}
+
+// -------------------------------------------------------------------
+
+/**
+ * Reads given configuration property. If not found, throws a
+ * MissingParameterException. Removes trailing whitespace characters.
+ * @param name
+ *          Name of configuration property
+ */
+public String getString(String name)
+{
+       try {
+               return getStr(name);
+       } catch (RuntimeException e) {
+               manageException(name, e);
+               return "";
+       }
+}
+
+/**
+ * The actual method implementing getString().
+ */
+private String getStr(String name)
+{
+       String result = config.getProperty(name);
+       if (result == null) {
+               throw new MissingParameterException(name);
+//                             "\nPossibly incorrect property: " + getSimilarProperty(name));
+       }
+       debug(name, "" + result);
+
+       return result.trim();
+}
+
+// -------------------------------------------------------------------
+
+/**
+ * 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 int getPid(String name)
+{
+       try {
+               String protname = getStr(name);
+               return lookupPid(protname);
+       } catch (RuntimeException e) {
+               manageException(name, e);
+               return 0;
+       }
+}
+
+// -------------------------------------------------------------------
+
+/**
+ * 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 int getPid(String name, int pid)
+{
+       try {
+               String protname = getStr(name);
+               return lookupPid(protname);
+       } catch (RuntimeException e) {
+               manageDefault(name, pid, e);
+               return 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 int lookupPid(String protname)
+{
+       Integer ret = protocols.get(protname);
+       if (ret == null) {
+               throw new MissingParameterException(Configuration.PAR_PROT + "." + protname);
+//                             "\nPossibly incorrect property: "
+//                             + getSimilarProperty(PAR_PROT + "." + protname));
+       }
+       return ret.intValue();
+}
+
+// -------------------------------------------------------------------
+
+/**
+ * Returns the name of a protocol that has the given identifier.
+ * <p>
+ * 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<String, Integer> i : protocols.entrySet()) {
+               if (i.getValue().intValue() == pid)
+                       return i.getKey();
+       }
+
+       // never reached but java needs it...
+       return null;
+}
+
+// -------------------------------------------------------------------
+
+/**
+ * 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 Class getClass(String name)
+{
+       try {
+               return getClazz(name);
+       } catch (RuntimeException e) {
+               manageException(name, e);
+               return null;
+       }
+}
+
+private Class getClazz(String name)
+{
+       String classname = config.getProperty(name);
+       if (classname == null) {
+               throw new MissingParameterException(name);
+//                             "\nPossibly incorrect property: " + getSimilarProperty(name));
+       }
+       debug(name, classname);
+
+       Class c = null;
+
+       try {
+               // Maybe classname is just a fully-qualified name
+               c = Class.forName(classname);
+       } catch (ClassNotFoundException e) {
+       }
+       if (c == null) {
+               // Maybe classname is a non-qualified name?
+               String fullname = ClassFinder.getQualifiedName(classname);
+               if (fullname != null) {
+                       try {
+                               c = Class.forName(fullname);
+                       } catch (ClassNotFoundException e) {
+                       }
+               }
+       }
+       if (c == null) {
+               // Maybe there are multiple classes with the same
+               // non-qualified name.
+               String fullname = ClassFinder.getQualifiedName(classname);
+               if (fullname != null) {
+                       String[] names = fullname.split(",");
+                       if (names.length > 1) {
+                               for (int i = 0; i < names.length; i++) {
+                                       for (int j = i + 1; j < names.length; j++) {
+                                               if (names[i].equals(names[j])) {
+                                                       throw new IllegalParameterException(name,
+                                                                       "The class " + names[i]
+                                                               + " appears more than once in the classpath; please check"
+                                                               + " your classpath to avoid duplications.");
+                                               }
+                                       }
+                               }
+                               throw new IllegalParameterException(name,
+                                               "The non-qualified class name " + classname
+                                                               + "corresponds to multiple fully-qualified classes:" + fullname);
+                       }
+               }
+       }
+       if (c == null) {
+               // Last attempt: maybe the fully classified name is wrong,
+               // but the classname is correct.
+               String shortname = ClassFinder.getShortName(classname);
+               String fullname = ClassFinder.getQualifiedName(shortname);
+               if (fullname != null) {
+                       throw new IllegalParameterException(name, "Class "
+                                       + classname + " does not exist. Possible candidate(s): " + fullname);
+               }
+       }
+       if (c == null) {
+               throw new IllegalParameterException(name, "Class "
+                               + classname + " not found");
+       }
+       return c;
+}
+
+// -------------------------------------------------------------------
+
+/**
+ * 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 Class getClass(String name, Class def)
+{
+
+       try {
+               return Configuration.getClass(name);
+       } catch (RuntimeException e) {
+               manageDefault(name, def, e);
+               return 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 <tt>name</tt>.
+ * 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 Object getInstance(String name)
+{
+  try {
+       return getInst(name);
+  } catch (RuntimeException e) {
+               manageException(name, e);
+               return null;
+  }
+}
+
+/**
+ * The actual method implementing getInstance().
+ */
+private Object getInst(String name)
+{
+       Class c = getClass(name);
+       if (c == null)
+               return null;
+       final String classname = c.getSimpleName();
+
+       try {
+               Class pars[] = {String.class};
+               Constructor cons = c.getConstructor(pars);
+               Object objpars[] = {name};
+               return cons.newInstance(objpars);
+       } catch (NoSuchMethodException e) {
+               throw new IllegalParameterException(name, "Class "
+                               + classname + " has no " + classname + "(String) constructor");
+       } catch (InvocationTargetException e) {
+               if (e.getTargetException() instanceof RuntimeException) {
+                       throw (RuntimeException) e.getTargetException();
+               } else {
+                       e.getTargetException().printStackTrace();
+                       throw new RuntimeException("" + e.getTargetException());
+               }
+       } catch (Exception e) {
+               throw new IllegalParameterException(name, e + "");
+       }
+}
+
+// -------------------------------------------------------------------
+
+/**
+ * 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 <tt>name</tt>.
+ * 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 Object getInstance(String name, Object def)
+{
+  if (!contains(name)) 
+       return def;
+       try {
+               return getInst(name);
+       } catch (RuntimeException e) {
+               manageException(name, e);
+               return 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 Object[] getInstanceArray(String name)
+{
+
+       String names[] = getNames(name);
+       Object[] result = new Object[names.length];
+
+       for (int i = 0; i < names.length; ++i) {
+               result[i] = getInstance(names[i]);
+       }
+
+       return result;
+}
+
+// -------------------------------------------------------------------
+
+/**
+ * Returns an array of names prefixed by the specified name. The array is
+ * sorted as follows. If there is no config entry
+ * <code>{@value peersim.config.Configuration#PAR_INCLUDE}+"."+name</code> or
+ * <code>{@value peersim.config.Configuration#PAR_ORDER}+"."+name</code> 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)
+{
+       ArrayList<String> ll = new ArrayList<String>();
+       final String pref = name + ".";
+
+       Enumeration e = config.propertyNames();
+       while (e.hasMoreElements()) {
+               String key = (String) e.nextElement();
+               if (key.startsWith(pref) && key.indexOf(".", pref.length()) < 0)
+                       ll.add(key);
+       }
+       String[] ret = ll.toArray(new String[ll.size()]);
+       return order(ret, name);
+}
+
+// -------------------------------------------------------------------
+
+/**
+ * The input of this method is a set of property <code>names</code> (e.g.
+ * initializers, controls and protocols) and a string specifying the type
+ * (prefix) of these. The output is in <code>names</code>, 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 <code>names</code>. Otherwise the configuration
+ * entry must contain entries from <code>names</code>. It is assumed
+ * that the entries in <code>names</code> contain only word characters
+ * (alphanumeric and underscore '_'. The order configuration entry thus
+ * contains a list of entries from <code>names</code> separated by any
+ * non-word characters.
+ * <p>
+ * 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<String> wordLetterPairs(String str)
+{
+       ArrayList<String> allPairs = new ArrayList<String>();
+       // Tokenize the string and put the tokens/words into an array
+       String[] words = str.split("\\s");
+       // For each word
+       for (int w = 0; w < words.length; w++) {
+               // Find the pairs of characters
+               String[] pairsInWord = letterPairs(words[w]);
+               for (int p = 0; p < pairsInWord.length; p++) {
+                       allPairs.add(pairsInWord[p]);
+               }
+       }
+       return allPairs;
+}
+
+// -------------------------------------------------------------------
+
+/**
+ * @return lexical similarity value in the range [0,1]
+ *         http://www.catalysoft.com/articles/StrikeAMatch.html
+ */
+private double compareStrings(String str1, String str2)
+{
+       ArrayList pairs1 = wordLetterPairs(str1.toUpperCase());
+       ArrayList pairs2 = wordLetterPairs(str2.toUpperCase());
+       int intersection = 0;
+       int union_ = pairs1.size() + pairs2.size();
+       for (int i = 0; i < pairs1.size(); i++) {
+               Object pair1 = pairs1.get(i);
+               for (int j = 0; j < pairs2.size(); j++) {
+                       Object pair2 = pairs2.get(j);
+                       if (pair1.equals(pair2)) {
+                               intersection++;
+                               pairs2.remove(j);
+                               break;
+                       }
+               }
+       }
+       return (2.0 * intersection) / union_;
+}
+
+// -------------------------------------------------------------------
+
+/**
+ * Among the defined properties, returns the one more similar to String
+ * property
+ */
+private String getSimilarProperty(String property)
+{
+       String bestProperty = null;
+       double bestValue = 0.0;
+       Enumeration e = config.keys();
+       while (e.hasMoreElements()) {
+               String key = (String) e.nextElement();
+               double compare = compareStrings(key, property);
+               if (compare > bestValue) {
+                       bestValue = compare;
+                       bestProperty = key;
+               }
+       }
+       return bestProperty;
+}
+
+//-------------------------------------------------------------------
+
+private void manageDefault(String name, Object def, 
+               RuntimeException e)
+{
+       debug(name, "" + def + " (DEFAULT)");
+       if (check) {
+               System.out.println("Warning: Property " + name + " = " + 
+                               def + " (DEFAULT)");
+       }
+       if (e instanceof MissingParameterException) {
+               // Do nothing
+       } else {
+               manageException(name, e);
+       }
+}
+
+//-------------------------------------------------------------------
+
+private void manageException(String name, RuntimeException e)
+{
+       if (check) {
+               if (e instanceof MissingParameterException) {
+                       // Print just the short message in this case
+                       System.out.println("Error: " + 
+                                       ((MissingParameterException) e).getShortMessage());
+               } else if (e instanceof IllegalParameterException) {
+                       // Print just the short message in this case
+                       System.out.println("Error: " + 
+                                       ((IllegalParameterException) e).getShortMessage());
+               } else {
+                       System.out.println("Error: " + e.getMessage());
+               }
+       } else {
+               throw e;
+       }
+}
+
+//-------------------------------------------------------------------
+
+}
diff --git a/contrib/psg/src/peersim/config/ConfigProperties.java b/contrib/psg/src/peersim/config/ConfigProperties.java
new file mode 100644 (file)
index 0000000..4f36892
--- /dev/null
@@ -0,0 +1,190 @@
+/*
+ * 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.Properties;
+import java.io.*;
+
+/**
+* Class for handling configuration files. Extends the functionality
+* of Properties by handling files, system resources and command lines.
+*/
+public class ConfigProperties extends Properties {
+
+
+// =========== Public Constructors ===================================
+// ===================================================================
+
+
+/**
+* Calls super constructor.
+*/
+public ConfigProperties() { super(); }
+
+// -------------------------------------------------------------------
+
+/**
+* Constructs a ConfigProperty object from a parameter list.
+* The algorithm is as follows: first <code>resource</code> is used to attempt
+* loading default values from the given system resource.
+* Then all Strings in <code>pars</code> are processed in the order they
+* appear in the array. For <code>pars[i]</code>, first a property file
+* with the name <code>pars[i]</code> is attempted to be loaded. If the file
+* does not exist or loading produces any other IOException, <code>pars[i]</code>
+* is interpreted as a property definition, and it is set.
+* <p>
+* A little inconvenience is that if <code>pars[i]</code> 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.
+* <p>
+* 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 <code>Properties.load</code> 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
+* <code>Properties.load</code> 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 (file)
index 0000000..4188111
--- /dev/null
@@ -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.
+ * <p>
+ * The design of this class also hides the actual implementation of the
+ * configuration which can be Properties, XML, whatever. Currently only
+ * Properties is supported.
+ * <p>
+ * 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.
+ * <p>
+ * 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.
+ * <h3>Typed reading of values</h3>
+ * 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.
+ * <h3>Resolving class names</h3>
+ * 
+ * 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.
+ * 
+ * <h3>Components and their ordering</h3>
+ * 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.
+ * 
+ * <p>
+ * 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,
+ * 
+ * <pre>
+ *   control.conn ConnectivityObserver
+ *   control.1 WireKOut
+ *   control.2 PrintGraph
+ * </pre>
+ * 
+ * defines control components of names "conn","1" an "2" (arguments of the
+ * components not shown). When {@link #getNames} or
+ * {@link #getInstanceArray} are called, eg
+ * <code>getNames("control")</code>, then the order in which these are
+ * returned is alphabetical:
+ * <code>["control.1","control.2","control.conn"]</code>. If you are not
+ * satisfied with lexicographic order, you can specify the order in this
+ * way.
+ * 
+ * <pre>
+ *   order.control 1,conn,2
+ * </pre>
+ * 
+ * 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.
+ * 
+ * <pre>
+ *   order.control 2
+ * </pre>
+ * 
+ * results in <code>["control.2","control.1","control.conn"]</code>.
+ * <p>
+ * 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 <code>include</code>. For example
+ * 
+ * <pre>
+ *   include.control conn 2
+ * </pre>
+ * 
+ * will result in returning <em>only</em> <code>control.conn</code> and
+ * <code>control.2</code>, in this order. Note that for example the
+ * empty list results in a zero length array in this case.
+ * <em>Important!</em> If include is defined then ordering is ignored.
+ * That is, include is stronger than order.
+ * <h3>Protocol names</h3>
+ * 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.
+ * <p>
+ * <h3>Expressions</h3>
+ * Numeric property values can be complex expressions, that are parsed
+ * using <a href="http://www.singularsys.com/jep/">JEP</a>. You can write
+ * expression using the syntax that you can find <a
+ * href="http://www.singularsys.com/jep/doc/html/op_and_func.html"> here</a>.
+ * For example,
+ * 
+ * <pre>
+ *   MAG 2
+ *   SIZE 2&circ;MAG
+ * </pre>
+ * 
+ * SIZE=4. You can also have complex expression trees like this:
+ * 
+ * <pre>
+ *   A B+C
+ *   B D+E
+ *   C E+F
+ *   D 1
+ *   E F
+ *   F 2
+ * </pre>
+ * 
+ * that results in A=7, B=3, C=4, D=1, E=2, F=2
+ * 
+ * <p>
+ * 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.
+ * 
+ * <p>
+ * 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.
+ * 
+ * <p>
+ * 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
+ * 
+ * <pre>
+ *   overlay.size SIZE
+ *   SIZE SIZE-1
+ * </pre>
+ * 
+ * you get an error message: Parameter "overlay.size": Probable recursive
+ * definition - exceeded maximum depth {@value #DEFAULT_MAXDEPTH}
+ * 
+ * <h3>Debug</h3>
+ * 
+ * It is possible to obtain debug information about the configuration
+ * properties by activating special configuration properties.
+ * <p>
+ * 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)".
+ * <p>
+ * 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.
+ * <p>
+ * Each line printed by this debug feature is prefixed by the string
+ * "DEBUG".
+ * 
+ * <h3>Use of brackets</h3>
+ * 
+ * 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.
+ * <p>
+ * 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 <tt>name</tt>.
+ * 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 <tt>name</tt>.
+ * 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
+ * <code>{@value #PAR_INCLUDE}+"."+name</code> or
+ * <code>{@value #PAR_ORDER}+"."+name</code> 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 (file)
index 0000000..d2eba1b
--- /dev/null
@@ -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
+ * <code>Configuration</code> 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; j<linkNames.length; ++j)
+                               links[i][j] = Configuration.lookupPid(linkNames[j]);
+               }               
+               else
+                       links[i] = new int[0]; // empty set
+
+               if (Configuration.contains(names[i] + "." + PAR_TRANSPORT))
+                       transports[i] = 
+                       Configuration.getPid(names[i] + "." + PAR_TRANSPORT);
+               else
+                       transports[i] = -1;
+       }
+}
+
+// ---------------------------------------------------------------------
+
+/** to prevent construction */
+private FastConfig() {}
+
+// ======================= methods ==========================================
+// ==========================================================================
+
+
+/**
+ * Returns true if the given protocol has at least one linkable protocol
+ * associated with it, otherwise false.
+ */
+public static boolean hasLinkable(int pid) { return numLinkables(pid) > 0; }
+
+// ---------------------------------------------------------------------
+
+/**
+ * Returns the number of linkable protocols associated with a given protocol.
+ */
+public static int numLinkables(int pid) { return links[pid].length; }
+
+// ---------------------------------------------------------------------
+
+/**
+ * Returns the protocol id of the <code>linkIndex</code>-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 <code>getLinkable(pid, 0)</code>.
+ */
+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 (file)
index 0000000..1285350
--- /dev/null
@@ -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 (file)
index 0000000..58b85cd
--- /dev/null
@@ -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 (file)
index 0000000..6124922
--- /dev/null
@@ -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 (file)
index 0000000..1d5d523
--- /dev/null
@@ -0,0 +1,163 @@
+/*\r
+ * Copyright (c) 2003-2005 The BISON Project\r
+ *\r
+ * This program is free software; you can redistribute it and/or modify\r
+ * it under the terms of the GNU Lesser General Public License version 2 as\r
+ * published by the Free Software Foundation.\r
+ *\r
+ * This program is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+ * GNU Lesser General Public License for more details.\r
+ *\r
+ * You should have received a copy of the GNU Lesser General Public License\r
+ * along with this program; if not, write to the Free Software\r
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\r
+ *\r
+ */\r
+package peersim.config;\r
+import java.math.*;\r
+import org.lsmp.djep.groupJep.groups.*;\r
+import org.lsmp.djep.groupJep.interfaces.*;\r
+\r
+/**\r
+ * This class implements the <code>Group</code> interface of JEP,\r
+ * enabling the configuration system to read integers with arbitrary \r
+ * length. \r
+ */\r
+public class Operators extends Group implements IntegralDomainI,HasDivI,\r
+       OrderedSetI,HasModI,HasPowerI {\r
+       \r
+\r
+       /**\r
+        * Operations on the reals (Implemented as BigInteger).\r
+        */\r
+       public Operators() {\r
+       }\r
+\r
+       public Number getZERO() {\r
+               return BigInteger.ZERO;\r
+       }\r
+\r
+       public Number getONE() {\r
+               return BigInteger.ONE;\r
+       }\r
+\r
+       public Number getInverse(Number num) {\r
+               if (num instanceof BigInteger) {\r
+                       BigInteger a = (BigInteger) num;\r
+                       return a.negate();\r
+               } else {\r
+                       return -num.doubleValue();\r
+               }\r
+       }\r
+\r
+       public Number add(Number num1, Number num2) {\r
+               if (num1 instanceof Double || num2 instanceof Double) {\r
+                       // One is double\r
+                       return num1.doubleValue() + num2.doubleValue();\r
+               } else {\r
+                       // Both integer\r
+                       BigInteger a = (BigInteger) num1;\r
+                       BigInteger b = (BigInteger) num2;\r
+                       return a.add(b);\r
+               }\r
+       }\r
+\r
+       public Number sub(Number num1, Number num2) {\r
+               if (num1 instanceof Double || num2 instanceof Double) {\r
+                       // One is double\r
+                       return num1.doubleValue() - num2.doubleValue();\r
+               } else {\r
+                       // Both integer\r
+                       BigInteger a = (BigInteger) num1;\r
+                       BigInteger b = (BigInteger) num2;\r
+                       return a.subtract(b);\r
+               }\r
+       }\r
+\r
+       public Number mul(Number num1, Number num2) {\r
+               if (num1 instanceof Double || num2 instanceof Double) {\r
+                       // One is double\r
+                       return num1.doubleValue() * num2.doubleValue();\r
+               } else {\r
+                       // Both integer\r
+                       BigInteger a = (BigInteger) num1;\r
+                       BigInteger b = (BigInteger) num2;\r
+                       return a.multiply(b);\r
+               }\r
+       }\r
+\r
+       public Number div(Number num1, Number num2) {\r
+               if (num1 instanceof Double || num2 instanceof Double) {\r
+                       // One is double\r
+                       return num1.doubleValue() / num2.doubleValue();\r
+               } else {\r
+                       // Both integer\r
+                       BigInteger a = (BigInteger) num1;\r
+                       BigInteger b = (BigInteger) num2;\r
+                       return a.divide(b);\r
+               }\r
+       }\r
+\r
+        \r
+       public Number mod(Number num1, Number num2) {\r
+               if (num1 instanceof Double || num2 instanceof Double) {\r
+                       // One is double\r
+                       return num1.doubleValue() % num2.doubleValue();\r
+               } else {\r
+                       // Both integer\r
+                       BigInteger a = (BigInteger) num1;\r
+                       BigInteger b = (BigInteger) num2;\r
+                       return a.remainder(b);\r
+               }\r
+       }\r
+       \r
+       public Number pow(Number num1, Number num2) {\r
+               if (num1 instanceof Double || num2 instanceof Double) {\r
+                       // One is double\r
+                       return Math.pow(num1.doubleValue(), num2.doubleValue());\r
+               } else {\r
+                       // Both integer\r
+                       BigInteger a = (BigInteger) num1;\r
+                       BigInteger b = (BigInteger) num2;\r
+                       return a.pow(b.intValue());\r
+               }\r
+       }\r
+       \r
+       public boolean equals(Number num1, Number num2) {\r
+               if (num1 instanceof Double || num2 instanceof Double) {\r
+                       // One is double\r
+                       return num1.doubleValue() == num2.doubleValue();\r
+               } else {\r
+                       // Both integer\r
+                       BigInteger a = (BigInteger) num1;\r
+                       BigInteger b = (BigInteger) num2;\r
+                       return a.equals(b);\r
+               }\r
+       }\r
+       \r
+       public int compare(Number num1,Number num2)     {\r
+               if (num1 instanceof Double || num2 instanceof Double) {\r
+                       // One is double\r
+                       double n1 = num1.doubleValue();\r
+                       double n2 = num2.doubleValue();\r
+                       return (n1 < n2 ? -1 : (n1 == n2 ? 0 : 1));\r
+               } else {\r
+                       // Both integer\r
+                       BigInteger a = (BigInteger) num1;\r
+                       BigInteger b = (BigInteger) num2;\r
+                       return a.compareTo(b);\r
+               }\r
+       }\r
+\r
+       public Number valueOf(String str) {\r
+               try {\r
+                       return new BigInteger(str);\r
+               } catch (NumberFormatException e) {\r
+                       return new Double(str);\r
+               }\r
+       }\r
+       \r
+       public String toString() { return ""; }\r
+}\r
diff --git a/contrib/psg/src/peersim/config/ParsedProperties.java b/contrib/psg/src/peersim/config/ParsedProperties.java
new file mode 100644 (file)
index 0000000..9a58e41
--- /dev/null
@@ -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 <code>Properties.load</code>
+* 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 <code>{</code> and <code>}</code>.
+  
+  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:
+  <pre>
+  control.degree GraphObserver 
+  {
+    protocol newscast
+    undir
+  }
+  </pre>
+  is equivalent to the definition of these three properties:
+  <pre>
+  control.degree GraphObserver 
+  control.degree.protocol newscast
+  control.degree.undir
+  </pre>
+  
+  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:
+  <pre>
+       control.1 DynamicNetwork
+       {
+         add CRASH
+         substitute
+         init.0 WireKOut 
+         {
+           degree DEGREE
+           protocol 0
+         }
+       }
+  </pre>
+  defines the following properties:
+  <pre>
+       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
+  </pre>
+  
+  <p>
+  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<String> prefixes = new HashSet<String>();
+       
+       BufferedReader f = 
+               new BufferedReader(new FileReader( fileName ));
+       int lines = 0;
+       parseStream(f, "", 0, lines, prefixes);
+
+       f.close();
+}
+
+// --------------------------------------------------------------------
+
+private int parseStream(BufferedReader f, String prefix, int pars, 
+               int lines, Set prefixes)
+throws IOException {
+
+       if (prefix.equals(".")) {
+               System.err.println("Error at line " + lines + ": bracket block not " +
+                               "associated with any configuration entry");
+               System.exit(1);
+       }
+       if (prefixes.contains(prefix)) {
+               System.err.println("Error at line " + lines + ": multiple bracket " +
+                               "blocks referring to the same configuration entry " + prefix);
+               System.exit(1);
+       } else {
+               prefixes.add(prefix);
+       }
+       
+       boolean complete = true;
+       String part;
+       String line = "";
+       String last = "";
+       while ((part = f.readLine()) != null)
+       {
+               lines++;
+               
+               // Reset line
+               if (complete) line = "";
+               
+               // Check if the line is a comment line
+               // If so, remove the comment
+               int index = part.indexOf('#');
+               if (index >= 0)
+               {
+                       part = part.substring(0, index);
+               } 
+
+               // Check if the line is empty
+               part = part.trim();
+               if ("".equals(part)) continue;
+
+               complete = (part.charAt(part.length()-1) != '\\'); 
+               if (!complete)
+               {  
+                       line = line + part.substring(0, part.length()-2) + " ";
+                       continue;
+               }
+               
+               // Complete the line
+               line = line + part;
+               if (line.equals("{"))
+               {
+                       lines = parseStream(f, last+".", pars+1, lines, prefixes);
+               } 
+               else if (line.equals("}"))
+               {
+                       if (pars == 0)
+                       {
+                               System.err.println(
+                                       "Error: Additional } at line " + lines + 
+                                       " when parsing the configuration file");
+                               System.exit(1);
+                       }
+                       return lines;
+               }
+               else
+               {
+                       // Search the first token
+                       String[] tokens = line.split("[\\s:=]+", 2);
+                       if (tokens.length == 1)
+                       {
+                               setProperty(prefix+tokens[0], "");
+                       }
+                       else
+                       {
+                               setProperty(prefix+tokens[0], tokens[1]);
+                       }
+                       last = prefix + tokens[0];
+               }
+       }
+       if (pars == 1)
+       {
+               System.err.println("Error: One closing bracket ('}') is missing");
+               System.exit(1);
+       } 
+       else if (pars > 1)
+       {
+               System.err.println("Error: " + pars+" closing brackets ('}') are missing");
+               System.exit(1);
+       }
+       return lines;
+}
+
+// --------------------------------------------------------------------
+
+/*
+public static void main(String[] args)
+{
+       java.util.Properties prop = new ParsedProperties(args);
+}
+*/
+}
+
diff --git a/contrib/psg/src/peersim/core/Cleanable.java b/contrib/psg/src/peersim/core/Cleanable.java
new file mode 100644 (file)
index 0000000..ac14f21
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * 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 interface must be implemented by protocols that need to release
+ * some references when the fail state of their host node is set to
+ * {@link Fallible#DEAD}. Recall that this fail state means that the node
+ * will never get back online. However, other nodes and protocols might
+ * still have references to these dead nodes and protocols, and this fact
+ * is not always a bug. So implementing this interface allows for removing
+ * stuff that we know is no longer necessary. Especially for linkable
+ * protocols in the presence of churn, this is essential: they typically
+ * have to release their links to other nodes to prevent the formation of
+ * trees of removed nodes with a live reference to the root.
+ */
+public interface Cleanable
+{
+
+/**
+ * Performs cleanup when removed from the network. This is called by the
+ * host node when its fail state is set to {@link Fallible#DEAD}.
+ * It is very important that after calling this method, NONE of the methods
+ * of the implementing object are guaranteed to work any longer.
+ * They might throw arbitrary exceptions, etc. The idea is that after
+ * calling this, typically no one should access this object.
+ * However, as a recommendation, at least toString should be guaranteed to
+ * execute normally, to aid debugging.
+ */
+public void onKill();
+
+}
diff --git a/contrib/psg/src/peersim/core/CommonState.java b/contrib/psg/src/peersim/core/CommonState.java
new file mode 100644 (file)
index 0000000..93b6e21
--- /dev/null
@@ -0,0 +1,301 @@
+/*
+ * 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 org.simgrid.msg.Msg;
+
+import peersim.Simulator;
+import peersim.config.*;
+import peersim.util.*;
+import psgsim.PSGPlatform;
+
+/**
+ * This is the common state of the simulation all objects see.
+ * Static singleton. One of its purposes is
+ * simplification of parameter structures and increasing efficiency by putting
+ * state information here instead of passing parameters.
+ *<p>
+ * <em>The set methods should not be used by applications</em>,
+ * 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.
+ * <ul>
+ * <li>{@link #PHASE_UNKNOWN} phase is unknown</li>
+ * <li>{@link #POST_SIMULATION} the simulation is completed</li>
+ * </ul>
+ */
+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 (file)
index 0000000..7644aa9
--- /dev/null
@@ -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 (file)
index 0000000..089cffe
--- /dev/null
@@ -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
+       * <code>getFailState()==OK</code>
+       */
+       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 (file)
index 0000000..2f2c02e
--- /dev/null
@@ -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
+* <code>prefix</code> 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; i<protocol.length; ++i) {
+               CommonState.setPid(i);
+               result.protocol[i] = (Protocol)protocol[i].clone();
+       }
+       return result;
+}
+
+// -----------------------------------------------------------------
+
+/** returns the next unique ID */
+private long nextID() {
+
+       return counterID++;
+}
+
+// =============== public methods ==================================
+// =================================================================
+
+
+public void setFailState(int failState) {
+       
+       // after a node is dead, all operations on it are errors by definition
+       if(failstate==DEAD && failState!=DEAD) throw new IllegalStateException(
+               "Cannot change fail state: node is already DEAD");
+       switch(failState)
+       {
+               case OK:
+                       failstate=OK;
+                       break;
+               case DEAD:
+                       //protocol = null;
+                       index = -1;
+                       failstate = DEAD;
+                       for(int i=0;i<protocol.length;++i)
+                               if(protocol[i] instanceof Cleanable)
+                                       ((Cleanable)protocol[i]).onKill();
+                       break;
+               case DOWN:
+                       failstate = DOWN;
+                       break;
+               default:
+                       throw new IllegalArgumentException(
+                               "failState="+failState);
+       }
+}
+
+// -----------------------------------------------------------------
+
+public int getFailState() { return failstate; }
+
+// ------------------------------------------------------------------
+
+public boolean isUp() { return failstate==OK; }
+
+// -----------------------------------------------------------------
+
+public Protocol getProtocol(int i) { return protocol[i]; }
+
+//------------------------------------------------------------------
+
+public int protocolSize() { return protocol.length; }
+
+//------------------------------------------------------------------
+
+public int getIndex() { return index; }
+
+//------------------------------------------------------------------
+
+public void setIndex(int index) { this.index = index; }
+       
+//------------------------------------------------------------------
+
+/**
+* Returns the ID of this node. The IDs are generated using a counter
+* (i.e. they are not random).
+*/
+public long getID() { return ID; }
+
+//------------------------------------------------------------------
+
+public String toString() 
+{
+       StringBuffer buffer = new StringBuffer();
+       buffer.append("ID: "+ID+" index: "+index+"\n");
+       for(int i=0; i<protocol.length; ++i)
+       {
+               buffer.append("protocol["+i+"]="+protocol[i]+"\n");
+       }
+       return buffer.toString();
+}
+
+//------------------------------------------------------------------
+
+/** Implemented as <code>(int)getID()</code>. */
+public int hashCode() { return (int)getID(); }
+
+}
+
+
diff --git a/contrib/psg/src/peersim/core/IdleProtocol.java b/contrib/psg/src/peersim/core/IdleProtocol.java
new file mode 100644 (file)
index 0000000..dd602d5
--- /dev/null
@@ -0,0 +1,160 @@
+/*
+ * 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.Configuration;
+
+/**
+ * A protocol that stores links. It does nothing apart from that.
+ * It is useful to model a static link-structure
+ * (topology). The only function of this protocol is to serve as a source of
+ * neighborhood information for other protocols.
+ */
+public class IdleProtocol implements Protocol, Linkable
+{
+
+// --------------------------------------------------------------------------
+// Parameters
+// --------------------------------------------------------------------------
+
+/**
+ * Default init capacity
+ */
+private static final int DEFAULT_INITIAL_CAPACITY = 10;
+
+/**
+ * Initial capacity. Defaults to {@value #DEFAULT_INITIAL_CAPACITY}.
+ * @config
+ */
+private static final String PAR_INITCAP = "capacity";
+
+// --------------------------------------------------------------------------
+// Fields
+// --------------------------------------------------------------------------
+
+/** Neighbors */
+protected Node[] neighbors;
+
+/** Actual number of neighbors in the array */
+protected int len;
+
+// --------------------------------------------------------------------------
+// Initialization
+// --------------------------------------------------------------------------
+
+public IdleProtocol(String s)
+{
+       neighbors = new Node[Configuration.getInt(s + "." + PAR_INITCAP,
+                       DEFAULT_INITIAL_CAPACITY)];
+       len = 0;
+}
+
+//--------------------------------------------------------------------------
+
+public Object clone()
+{
+       IdleProtocol ip = null;
+       try { ip = (IdleProtocol) super.clone(); }
+       catch( CloneNotSupportedException e ) {} // never happens
+       ip.neighbors = new Node[neighbors.length];
+       System.arraycopy(neighbors, 0, ip.neighbors, 0, len);
+       ip.len = len;
+       return ip;
+}
+
+// --------------------------------------------------------------------------
+// Methods
+// --------------------------------------------------------------------------
+
+public boolean contains(Node n)
+{
+       for (int i = 0; i < len; i++) {
+               if (neighbors[i] == n)
+                       return true;
+       }
+       return false;
+}
+
+// --------------------------------------------------------------------------
+
+/** Adds given node if it is not already in the network. There is no limit
+* to the number of nodes that can be added. */
+public boolean addNeighbor(Node n)
+{
+       for (int i = 0; i < len; i++) {
+               if (neighbors[i] == n)
+                       return false;
+       }
+       if (len == neighbors.length) {
+               Node[] temp = new Node[3 * neighbors.length / 2];
+               System.arraycopy(neighbors, 0, temp, 0, neighbors.length);
+               neighbors = temp;
+       }
+       neighbors[len] = n;
+       len++;
+       return true;
+}
+
+// --------------------------------------------------------------------------
+
+public Node getNeighbor(int i)
+{
+       return neighbors[i];
+}
+
+// --------------------------------------------------------------------------
+
+public int degree()
+{
+       return len;
+}
+
+// --------------------------------------------------------------------------
+
+public void pack()
+{
+       if (len == neighbors.length)
+               return;
+       Node[] temp = new Node[len];
+       System.arraycopy(neighbors, 0, temp, 0, len);
+       neighbors = temp;
+}
+
+// --------------------------------------------------------------------------
+
+public String toString()
+{
+       if( neighbors == null ) return "DEAD!";
+       StringBuffer buffer = new StringBuffer();
+       buffer.append("len=" + len + " maxlen=" + neighbors.length + " [");
+       for (int i = 0; i < len; ++i) {
+               buffer.append(neighbors[i].getIndex() + " ");
+       }
+       return buffer.append("]").toString();
+}
+
+// --------------------------------------------------------------------------
+
+public void onKill()
+{
+       neighbors = null;
+       len = 0;
+}
+
+}
diff --git a/contrib/psg/src/peersim/core/Linkable.java b/contrib/psg/src/peersim/core/Linkable.java
new file mode 100644 (file)
index 0000000..962b427
--- /dev/null
@@ -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.core;
+
+
+/**
+* Instances of classes implementing this interface can form networks (graphs)
+* in the simulator framework.
+* The interface is similar to one of a container (containing neighbors),
+* only the types of the contained elements have to be {@link Node}.
+* The neighbor collection is defined in a random access list style, but
+* it must follow the contract of a set too (elements must be unique).
+* <p>
+* 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 (file)
index 0000000..26ed74f
--- /dev/null
@@ -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 (file)
index 0000000..7ce80a3
--- /dev/null
@@ -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 (file)
index 0000000..da9c545
--- /dev/null
@@ -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.
+ * <p>
+ * 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}.
+        * <p>
+        * 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 (file)
index 0000000..a64e3a2
--- /dev/null
@@ -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 <code>i</code>-th protocol in this node. If <code>i</code> 
+ * 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
+ * <code>Network.get(n.getIndex())</code> 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 <code>hashCode()</code> 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
+ * <code>throws</code> 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 (file)
index 0000000..4d1896f
--- /dev/null
@@ -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 <tt>this</tt> 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 (file)
index 0000000..0009459
--- /dev/null
@@ -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 Collection<Integer> getNeighbours(int i) {
+       
+       Linkable lble=(Linkable)Network.node[i].getProtocol(protocolID);
+       ArrayList<Integer> al = new ArrayList<Integer>(lble.degree());
+       if( Network.node[i].isUp() )
+       {       
+               for(int j=0; j<lble.degree(); ++j)
+               {
+                       final Node n = lble.getNeighbor(j);
+                       // if accessible, we include it
+                       if(n.isUp()) al.add(Integer.valueOf(n.getIndex()));
+               }
+       }
+       return Collections.unmodifiableList(al);
+}
+
+// ---------------------------------------------------------------
+
+/** Returns <code>Network.node[i]</code> */
+public Object getNode(int i) { return Network.node[i]; }
+       
+// ---------------------------------------------------------------
+
+/**
+* Returns null always
+*/
+public Object getEdge(int i, int j) { return null; }
+
+// ---------------------------------------------------------------
+
+/** Returns <code>Network.size()</code> */
+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.
+*
+* <p>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.
+*
+* <p>
+* 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<lble.degree(); ++j)
+       {
+               final Node n = lble.getNeighbor(j);
+               // if accessible, we count it
+               if(n.isUp()) numNeighbours++;
+       }
+       return numNeighbours;
+}
+
+
+// ========================= other methods =======================
+// ===============================================================
+
+
+/**
+* Returns number of neighbors that are either up or down.
+* If node i is down, returns 0.
+*/
+public int fullDegree(int i) {
+
+       if( !Network.node[i].isUp() ) return 0;
+       Linkable lble=(Linkable)Network.node[i].getProtocol(protocolID);
+       return lble.degree();
+}
+
+
+}
+
+
diff --git a/contrib/psg/src/peersim/core/Protocol.java b/contrib/psg/src/peersim/core/Protocol.java
new file mode 100644 (file)
index 0000000..04e8ecf
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * 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;
+
+/**
+ * Interface to identify protocols.
+ * 
+ * @author Alberto Montresor
+ * @version $Revision: 1.5 $
+ */
+public interface Protocol extends Cloneable
+{
+
+/**
+ * Returns a clone of the protocol. It is important to pay attention to
+ * implement this carefully because in peersim all nodes are generated by
+ * cloning except a prototype node. That is, the constructor of protocols is
+ * used only to construct the prototype. Initialization can be done
+ * via {@link Control}s.
+ */
+public Object clone();
+
+}
diff --git a/contrib/psg/src/peersim/core/Scheduler.java b/contrib/psg/src/peersim/core/Scheduler.java
new file mode 100644 (file)
index 0000000..035f982
--- /dev/null
@@ -0,0 +1,186 @@
+/*
+ * 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.*;
+
+// XXX a quite primitive scheduler, should be able to be configured
+// much more flexibly using a simple syntax for time ranges.
+/**
+* A binary function over the time points. That is,
+* for each time point returns a boolean value.
+* 
+* The concept of time depends on the simulation model. Current time
+* has to be set by the simulation engine, irrespective of the model,
+* and can be read using {@link CommonState#getTime()}. This scheduler
+* is interpreted over those time points.
+*
+* <p>In this simple implementation the valid times will be
+* <tt>from, from+step, from+2*step, etc,</tt>
+* where the last element is strictly less than <tt>until</tt>.
+* Alternatively, if <tt>at</tt> is defined, then the schedule will be a single
+* time point. If FINAL is
+* defined, it is also added to the set of active time points.
+* It refers to the time after the simulation has finished (see
+* {@link CommonState#getPhase}).
+*/
+public class Scheduler {
+
+
+// ========================= fields =================================
+// ==================================================================
+
+
+/**
+* Defaults to 1.
+* @config
+*/
+private static final String PAR_STEP = "step";
+
+/** 
+* Defaults to -1. That is, defaults to be ineffective.
+* @config
+*/
+private static final String PAR_AT = "at";
+
+
+/** 
+* Defaults to 0.
+* @config
+*/
+private static final String PAR_FROM = "from";
+
+/** 
+* Defaults to <tt>Long.MAX_VALUE</tt>.
+* @config
+*/
+private static final String PAR_UNTIL = "until";
+
+/**
+* Defines if component is active after the simulation has finished.
+* Note that the exact time the simulation finishes is not know in advance
+* because other components can stop the simulation at any time.
+* By default not set.
+* @see CommonState#getPhase
+* @config
+*/
+private static final String PAR_FINAL = "FINAL";
+
+public final long step;
+
+public final long from;
+
+public final long until;
+
+public final boolean fin;
+
+/** The next scheduled time point.*/
+protected long next = -1;
+
+// ==================== initialization ==============================
+// ==================================================================
+
+
+/** Reads configuration parameters from the component defined by
+* <code>prefix</code>. {@value #PAR_STEP} defaults to 1.
+*/
+public Scheduler(String prefix) {
+       
+       this(prefix, true);
+}
+
+// ------------------------------------------------------------------
+
+/** Reads configuration parameters from the component defined by
+* <code>prefix</code>. 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 (file)
index 0000000..a581a86
--- /dev/null
@@ -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:
+        * 
+        * <pre>
+        * control.0 DynamicNetwork
+        * control.0.init.0 RandNI
+        * control.0.init.0.k 5
+        * control.0.init.0.protocol somelinkable
+        * ...
+        * </pre>
+        * 
+        * @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 <tt>add*networksize</tt>. 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 <em>random</em> nodes
+        * <em>permanently</em> 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 (file)
index 0000000..5e9e5fc
--- /dev/null
@@ -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.
+ * <p>
+ * 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<Integer> pids = new ArrayList<Integer>();
+               ArrayList<Method> methods = new ArrayList<Method>();
+               for(int i=0; i<Network.prototype.protocolSize(); ++i)
+               {
+                       Method m = null;
+                       try
+                       {
+                               m = MethodInvoker.getMethod(
+                                 Network.prototype.getProtocol(i).getClass(),
+                                 methodName );
+                       }
+                       catch(NoSuchMethodException e) {}
+                       
+                       if(m!=null)
+                       {
+                               pids.add(i);
+                               methods.add(m);
+                       }
+               }
+
+               if( pids.isEmpty() )
+               {
+                       throw new IllegalParameterException(prefix + "." +
+                       PAR_METHOD,
+                       "No protocols found that implement 'void "+
+                       methodName+"()'");
+               }
+
+               pid=new int[pids.size()];
+               int j=0;
+               for(int i: pids) pid[j++]=i;
+               method=methods.toArray(new Method[methods.size()]);
+       }
+       else
+       {
+               pid = new int[1];
+               pid[0] = Configuration.getPid(prefix+"."+PAR_PROT);
+               try
+               {
+                       method = new Method[1];
+                       method[0]=MethodInvoker.getMethod(
+                         Network.prototype.getProtocol(pid[0]).getClass(),
+                         methodName );
+               }
+               catch (NoSuchMethodException e)
+               {
+                       throw new IllegalParameterException(prefix + "." +
+                       PAR_METHOD, e+"");
+               }
+       }
+}
+
+// --------------------------------------------------------------------------
+// Methods
+// --------------------------------------------------------------------------
+
+private static Method getMethod(Class cl, String methodName)
+throws NoSuchMethodException {
+
+       Method[] methods = cl.getMethods();
+       ArrayList<Method> list = new ArrayList<Method>();
+       for(Method m: methods)
+       {
+               if(m.getName().equals(methodName))
+               {
+                       Class[] pars = m.getParameterTypes();
+                       Class ret = m.getReturnType();
+                       if( pars.length == 0 && ret==void.class )
+                               list.add(m);
+               }
+       }
+       
+       if(list.size() == 0)
+       {
+               throw new NoSuchMethodException("Method "
+               + methodName + " in class " + cl.getName());
+       }
+       
+       return list.get(0);
+}
+
+//--------------------------------------------------------------------------
+
+/** Invokes method on all the nodes. */
+public boolean execute() {
+
+       for(int i=0; i<Network.size(); ++i)
+       {
+               initialize(Network.get(i));
+       }
+
+       return false;
+}
+
+//--------------------------------------------------------------------------
+
+/** Invokes method on given node. */
+public void initialize(Node n) {
+       
+       try
+       {
+               for(int i=0; i<pid.length; ++i)
+               {
+                       CommonState.setNode(n);
+                       CommonState.setPid(pid[i]);
+                       method[i].invoke(n.getProtocol(pid[i]));
+               }
+       }
+       catch(Exception e)
+       {
+               e.printStackTrace();
+               System.exit(1);
+       }
+}
+}
diff --git a/contrib/psg/src/peersim/dynamics/NodeInitializer.java b/contrib/psg/src/peersim/dynamics/NodeInitializer.java
new file mode 100644 (file)
index 0000000..7049a11
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * 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.Node;
+
+/**
+ * Generic interface to initialize a node before inserting it into the
+ * simulation. Other components like {@link DynamicNetwork} can use a
+ * NodeInitializer. It is designed to allow maximal flexibility therefore poses
+ * virtually no restrictions on the implementation. It can even be used to
+ * implement initializations that require global knowledge of the system.
+ */
+public interface NodeInitializer
+{
+
+/**
+ * Performs arbitrary initializations on the given node. It is guaranteed that
+ * this is called <em>before</em> inserting the node into the network.
+ */
+public void initialize(Node n);
+
+}
diff --git a/contrib/psg/src/peersim/dynamics/OscillatingNetwork.java b/contrib/psg/src/peersim/dynamics/OscillatingNetwork.java
new file mode 100644 (file)
index 0000000..4c10f2d
--- /dev/null
@@ -0,0 +1,200 @@
+/*
+ * 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.config.Configuration;
+import peersim.core.*;
+
+/**
+ * Makes the network size oscillate.
+ * The network size will be the function of time, parameterized by this
+ * parameter. The size function is
+ * <code>avg+sin(time*pi/{@value #PAR_PERIOD})*ampl</code> where
+ * <code>avg=({@value #PAR_MAX}+{@value #PAR_MIN})/2</code> and 
+ * <code>ampl=({@value #PAR_MAX}-{@value #PAR_MIN})/2</code>.
+ * 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:
+ * <pre>
+control.0 DynamicNetwork
+control.0.init.0 RandNI
+control.0.init.0.k 5
+control.0.init.0.protocol somelinkable
+...
+ * </pre>
+ * @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
+ * <code>avg+sin(time*pi/{@value #PAR_PERIOD})*ampl</code> where
+ * <code>avg=({@value #PAR_MAX}+{@value #PAR_MIN})/2</code> and 
+ * <code>ampl=({@value #PAR_MAX}-{@value #PAR_MIN})/2</code>.
+ * @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 <em>random</em>
+ * nodes <em>permanently</em> 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
+ * <code>avg+sin(time*pi/{@value #PAR_PERIOD})*ampl</code> where
+ * <code>avg=({@value #PAR_MAX}+{@value #PAR_MIN})/2</code> and 
+ * <code>ampl=({@value #PAR_MAX}-{@value #PAR_MIN})/2</code>.
+ * 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 (file)
index 0000000..7a4d5c7
--- /dev/null
@@ -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 (file)
index 0000000..4dbd866
--- /dev/null
@@ -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()) && i<Network.size(); ++i)
+               center=Network.get(i);
+       
+       ((Linkable)n.getProtocol(pid)).addNeighbor(center);
+       
+       if(pack)
+       {
+               ((Linkable)n.getProtocol(pid)).pack();
+       }
+}
+
+}
+
diff --git a/contrib/psg/src/peersim/dynamics/WireByMethod.java b/contrib/psg/src/peersim/dynamics/WireByMethod.java
new file mode 100644 (file)
index 0000000..de32a69
--- /dev/null
@@ -0,0 +1,223 @@
+/*
+ * 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.graph.*;
+import peersim.core.*;
+import peersim.config.*;
+import java.lang.reflect.*;
+import java.util.ArrayList;
+
+/**
+ * Takes a {@link Linkable} protocol and adds connections using an arbitrary
+ * method.
+ * No connections are removed.
+ * The connections are added by an arbitrary method that can be specified
+ * in the configuration. 
+ * The properties the method has to fulfill are the following
+ <ul>
+ <li>It MUST be static</li>
+ <li>It MUST have a first argument that can be assigned from a class
+ that implements {@link Graph}.</li>
+ <li>It MAY contain zero or more arguments following the first one.</li>
+ <li>All the arguments after the first one MUST be of primitive type int,
+ long or double, except
+ the last one, which MAY be of type that can be assigned from
+ <code>java.util.Random</code></li>
+ </ul>
+ The arguments are initialized using the configuration as follows.
+ <ul>
+ <li>The first argument is the {@link Graph} that is passed to
+ {@link #wire}.</li>
+ <li>The arguments after the first one (indexed as 1,2,etc) are initialized
+ from configuration parameters of the form {@value #PAR_ARG}i, where i is the
+ index.
+ <li>If the last argument can be assigned from 
+ <code>java.util.Random</code> then it is initialized with
+ {@link CommonState#r}, the central source of randomness for the
+ simulator.</li>
+ </ul>
+ For example, the class {@link WireWS} can be emulated by configuring
+ <pre>
+ init.0 WireByMethod
+ init.0.class GraphFactory
+ init.0.method wireWS
+ init.0.arg1 10
+ init.0.arg2 0.1
+ ...
+ </pre>
+ 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 <code>wire</code>.
+* @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; i<args.length; ++i)
+       {
+               
+               if( argt[i]==int.class )
+                       args[i]=Configuration.getInt(prefix+"."+PAR_ARG+i);
+               else if( argt[i]==long.class )
+                       args[i]=Configuration.getLong(prefix+"."+PAR_ARG+i);
+               else if( argt[i]==double.class )
+                       args[i]=Configuration.getDouble(prefix+"."+PAR_ARG+i);
+               else if(i==args.length-1 && argt[i].isInstance(CommonState.r))
+                       args[i]=CommonState.r;
+               else
+               {
+                       // we should neve get here
+                       throw new RuntimeException("Unexpected error, please "+
+                       "report this problem to the peersim team");
+               }
+       }
+}
+
+//--------------------------------------------------------------------------
+
+/**
+ * Search a wiring method in the specified class.
+ * @param cl
+ *          the class where to find the method
+ * @param methodName
+ *          the method to be searched
+ * @return the requested method, if it fully conforms to the definition of
+ * the wiring methods.
+ */
+private static Method getMethod(Class cl, String methodName)
+               throws NoSuchMethodException, ClassNotFoundException {
+               
+       // Search methods
+       Method[] methods = cl.getMethods();
+       ArrayList<Method> list = new ArrayList<Method>();
+       for (Method m: methods) {
+               if (m.getName().equals(methodName)) {
+                       list.add(m);
+               }
+       }
+       
+       if (list.size() == 0) {
+               throw new NoSuchMethodException("No method "
+               + methodName + " in class " + cl.getSimpleName());
+       } else if (list.size() > 1) {
+               throw new NoSuchMethodException("Multiple methods called "
+               + methodName + " in class " + cl.getSimpleName());
+       }
+       
+       // Found a single method with the right name; check if
+       // it is a setter.
+       final Class graphClass = Class.forName("peersim.graph.Graph");
+       final Class randomClass = Class.forName("java.util.Random");
+       Method method = list.get(0);
+       Class[] pars = method.getParameterTypes();
+       if( pars.length < 1 || !pars[0].isAssignableFrom(graphClass) )
+               throw new NoSuchMethodException(method.getName() + " of class "
+               + cl.getSimpleName() + " is not a valid graph wiring method,"+
+               " it has to have peersim.graph.Graph as first argument type");
+       for(int i=1; i<pars.length; ++i)
+               if( !( pars[i]==int.class || pars[i]==long.class ||
+               pars[i]==double.class ||
+               (i==pars.length-1 && pars[i].isAssignableFrom(randomClass)) ) )
+                       throw new NoSuchMethodException(method.getName() +
+                       " of class "+ cl.getSimpleName()
+                       + " is not a valid graph wiring method");
+                       
+       if(method.toString().indexOf("static")<0)
+               throw new NoSuchMethodException(method.getName() +
+               " of class "+ cl.getSimpleName()
+               + " is not a valid graph wiring method; it is not static");
+       
+       return method;
+}
+
+
+//--------------------------------------------------------------------------
+//Methods
+//--------------------------------------------------------------------------
+
+/** Invokes the method passing g to it.*/
+public void wire(Graph g) {
+
+       args[0]=g;
+       try { method.invoke(null,args); }
+       catch( Exception e ) { throw new RuntimeException(e); }
+}
+
+}
+
diff --git a/contrib/psg/src/peersim/dynamics/WireFromFile.java b/contrib/psg/src/peersim/dynamics/WireFromFile.java
new file mode 100644 (file)
index 0000000..2b40636
--- /dev/null
@@ -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.dynamics;
+
+
+import java.io.IOException;
+import java.io.FileReader;
+import java.io.LineNumberReader;
+import java.util.StringTokenizer;
+import peersim.graph.Graph;
+import peersim.core.*;
+import peersim.config.Configuration;
+
+/**
+* Takes a {@link Linkable} protocol and adds connections that are stored in a
+* file. Note that no
+* connections are removed, they are only added. So it can be used in
+* combination with other initializers.
+* The format of the file is as follows. Each line begins with a node ID
+* (IDs start from 0) followed by a list of neighbors, separated by whitespace.
+* All node IDs larger than the actual network size will be discarded, but
+* it does not trigger an error. Lines starting with a "#" character and
+* empty lines are ignored.
+*/
+public class WireFromFile extends WireGraph {
+
+
+// ========================= fields =================================
+// ==================================================================
+
+
+/** 
+*  The filename to load links from.
+*  @config
+*/
+private static final String PAR_FILE = "file";
+
+/** 
+*  The number of neighbors to be read from the file. If unset, the default
+* behavior is to read all links in the file. If set, then the first k
+* neighbors will be read only.
+*  @config
+*/
+private static final String PAR_K = "k";
+
+private final String file;
+
+private final int k;
+
+// ==================== initialization ==============================
+// ==================================================================
+
+
+/**
+ * Standard constructor that reads the configuration parameters.
+ * Invoked by the simulation engine.
+ * @param prefix the configuration prefix for this class
+ */
+public WireFromFile(String prefix) {
+
+       super(prefix);
+       file = Configuration.getString(prefix+"."+PAR_FILE);
+       k = Configuration.getInt(prefix + "." + PAR_K, Integer.MAX_VALUE);
+}
+
+
+// ===================== public methods ==============================
+// ===================================================================
+
+
+/**
+* Wires the graph from a file.
+* The format of the file is as follows. Each line begins with a node ID
+* (IDs start from 0) followed by a list of neighbors, separated by whitespace.
+* All node IDs larger than the actual network size will be discarded, but
+* it does not trigger an error. Lines starting with a "#" character and
+* empty lines are ignored.
+*/
+public void wire(Graph g) {
+try
+{
+       FileReader fr = new FileReader(file);
+       LineNumberReader lnr = new LineNumberReader(fr);
+       String line;
+       boolean wasOutOfRange=false;
+       while((line=lnr.readLine()) != null)
+       {
+               if( line.startsWith("#") ) continue;
+               StringTokenizer st = new StringTokenizer(line);
+               if(!st.hasMoreTokens()) continue;
+               
+               final int from = Integer.parseInt(st.nextToken());
+               if( from < 0 || from >= Network.size() )
+               {
+                       wasOutOfRange = true;
+                       continue;
+               }
+               
+               for(int i=0; i<k && st.hasMoreTokens(); ++i)
+               {
+                       final int to = Integer.parseInt(st.nextToken());
+                       if( to < 0 || to >= Network.size() )
+                               wasOutOfRange = true;
+                       else
+                               g.setEdge(from,to);
+               }
+       }
+
+       if( wasOutOfRange )
+               System.err.println("WireFromFile warning: in "+file+" "+
+                       "some nodes were out of range and so ignored.");
+       lnr.close();
+}
+catch( IOException e )
+{
+       throw new RuntimeException(e);
+}
+}
+
+}
diff --git a/contrib/psg/src/peersim/dynamics/WireGraph.java b/contrib/psg/src/peersim/dynamics/WireGraph.java
new file mode 100644 (file)
index 0000000..4c8af15
--- /dev/null
@@ -0,0 +1,158 @@
+/*
+ * 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.graph.Graph;
+import peersim.core.*;
+import peersim.config.Configuration;
+
+/**
+ * This class is the superclass of classes that
+ * takes a {@link Linkable} protocol or a graph and add edges that define a
+ * certain topology.
+ * Note that no connections are removed, they are only added. So it can be used
+ * in combination with other initializers.
+ */
+public abstract class WireGraph implements Control
+{
+
+// --------------------------------------------------------------------------
+// Parameters
+// --------------------------------------------------------------------------
+
+/**
+ * The {@link Linkable} protocol to operate on. If it is not specified,
+ * then operates on {@link #g}. If {@link #g} is null, {@link #execute} throws
+ * an Exception. Note that if {@link #g} is set, it will be used irrespective
+ * of the setting of the protocol in this field.
+ * @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";
+
+/**
+ * If set, the generated graph is undirected. In other words, for each link
+ * (i,j) a link (j,i) will also be added. Defaults to false.
+ * @config
+ */
+private static final String PAR_UNDIR = "undir";
+
+/**
+* Alias for {@value #PAR_UNDIR}.
+* @config
+*/
+private static final String PAR_UNDIR_ALT = "undirected";
+
+// --------------------------------------------------------------------------
+// Fields
+// --------------------------------------------------------------------------
+
+/**
+ * The protocol we want to wire. It is negative if no protocol was set
+ * (in that case, a graph must be specified, see {@link #g}).
+ */
+protected final int pid;
+
+/** If true, method pack() is invoked on the initialized protocol */
+private final boolean pack;
+
+/** If true, edges are added in an undirected fashion.*/
+public final boolean undir;
+
+/**
+* If set (not null), this is the graph to wire. If null, the current overlay
+* is wired each time {@link #execute} is called, as specified by {@value
+* #PAR_PROT}.
+*/
+public Graph g=null;
+
+// --------------------------------------------------------------------------
+// Initialization
+// --------------------------------------------------------------------------
+
+/**
+ * Standard constructor that reads the configuration parameters. Normally
+ * invoked by the simulation engine.
+ * @param prefix
+ *          the configuration prefix for this class
+ */
+protected WireGraph(String prefix) {
+
+       if( Configuration.contains(prefix + "." + PAR_PROT) )
+               pid = Configuration.getPid(prefix + "." + PAR_PROT);
+       else
+               pid = -10;
+       pack = Configuration.contains(prefix + "." + PAR_PACK);
+       undir = (Configuration.contains(prefix + "." + PAR_UNDIR) |
+               Configuration.contains(prefix + "." + PAR_UNDIR_ALT));
+}
+
+
+//--------------------------------------------------------------------------
+//Public methods
+//--------------------------------------------------------------------------
+
+/**
+* Calls method {@link #wire} with the graph {@link #g},
+* or if null, on the overlay specified by the protocol given by config
+* parameter {@value #PAR_PROT}. If neither {@link #g}, nor {@value #PAR_PROT}
+* is set, throws a RuntimException.
+*/
+public final boolean execute() {
+
+       Graph gr;
+       if(g==null && pid==-10)
+       {
+               throw new RuntimeException(
+                       "Neither a protocol, nor a graph is specified.");
+       }
+       if(g==null) gr = new OverlayGraph(pid,!undir);
+       else gr=g;
+
+       if(gr.size()==0) return false;
+       wire(gr);
+       
+       if( g==null && pack)
+       {
+               int size = Network.size();
+               for (int i = 0; i < size; i++)
+               {
+                       Linkable link =
+                               (Linkable) Network.get(i).getProtocol(pid);
+                       link.pack();
+               }
+       }
+       return false;
+}
+
+//--------------------------------------------------------------------------
+
+/** The method that should wire (add edges to) the given graph. Has to
+* be implemented by extending classes */
+public abstract void wire(Graph g);
+
+}
+
diff --git a/contrib/psg/src/peersim/dynamics/WireKOut.java b/contrib/psg/src/peersim/dynamics/WireKOut.java
new file mode 100644 (file)
index 0000000..927ddbd
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * 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.graph.*;
+import peersim.core.*;
+import peersim.config.*;
+
+/**
+ * Takes a {@link Linkable} protocol and adds random connections. Note that no
+ * connections are removed, they are only added. So it can be used in
+ * combination with other initializers.
+ * @see GraphFactory#wireKOut
+ */
+public class WireKOut extends WireGraph {
+
+//--------------------------------------------------------------------------
+//Parameters
+//--------------------------------------------------------------------------
+
+/**
+ * The number of outgoing edges to generate from each node.
+ * Passed to {@link GraphFactory#wireKOut}.
+ * No loop edges are generated.
+ * In the undirected case, the degree
+ * of nodes will be on average almost twice as much because the incoming links
+ * also become links out of each node.
+ * @config
+ */
+private static final String PAR_DEGREE = "k";
+
+//--------------------------------------------------------------------------
+//Fields
+//--------------------------------------------------------------------------
+
+/**
+ * The number of outgoing edges to generate from each node.
+ */
+private final int k;
+
+//--------------------------------------------------------------------------
+//Initialization
+//--------------------------------------------------------------------------
+
+/**
+ * Standard constructor that reads the configuration parameters.
+ * Invoked by the simulation engine.
+ * @param prefix the configuration prefix for this class
+ */
+public WireKOut(String prefix)
+{
+       super(prefix);
+       k = Configuration.getInt(prefix + "." + PAR_DEGREE);
+}
+
+//--------------------------------------------------------------------------
+//Methods
+//--------------------------------------------------------------------------
+
+/** Calls {@link GraphFactory#wireKOut}. */
+public void wire(Graph g) {
+
+       GraphFactory.wireKOut(g,k,CommonState.r);
+}
+
+}
diff --git a/contrib/psg/src/peersim/dynamics/WireRegRootedTree.java b/contrib/psg/src/peersim/dynamics/WireRegRootedTree.java
new file mode 100644 (file)
index 0000000..e8e0952
--- /dev/null
@@ -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.dynamics;
+
+import peersim.graph.*;
+import peersim.config.*;
+
+/**
+ * Takes a {@link peersim.core.Linkable} protocol and adds connections that
+ * define a regular
+ * rooted tree. Note that no
+ * connections are removed, they are only added. So it can be used in
+ * combination with other initializers.
+ * @see #wire
+ * @see GraphFactory#wireRegRootedTree
+ */
+public class WireRegRootedTree extends WireGraph {
+
+//--------------------------------------------------------------------------
+//Parameters
+//--------------------------------------------------------------------------
+
+/**
+ * The parameter of the tree wiring method.
+ * It is passed to {@link GraphFactory#wireRegRootedTree}.
+ * @config
+ */
+private static final String PAR_DEGREE = "k";
+
+//--------------------------------------------------------------------------
+//Fields
+//--------------------------------------------------------------------------
+
+private final int k;
+
+//--------------------------------------------------------------------------
+//Initialization
+//--------------------------------------------------------------------------
+
+/**
+ * Standard constructor that reads the configuration parameters.
+ * Invoked by the simulation engine.
+ * @param prefix the configuration prefix for this class
+ */
+public WireRegRootedTree(String prefix)
+{
+       super(prefix);
+       k = Configuration.getInt(prefix + "." + PAR_DEGREE);
+}
+
+//--------------------------------------------------------------------------
+//Methods
+//--------------------------------------------------------------------------
+
+/** Calls {@link GraphFactory#wireRegRootedTree}. */
+public void wire(Graph g) {
+
+       GraphFactory.wireRegRootedTree(g,k);
+}
+
+}
diff --git a/contrib/psg/src/peersim/dynamics/WireRingLattice.java b/contrib/psg/src/peersim/dynamics/WireRingLattice.java
new file mode 100644 (file)
index 0000000..a23822e
--- /dev/null
@@ -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.dynamics;
+
+import peersim.graph.*;
+import peersim.config.Configuration;
+
+/**
+ * Takes a {@link peersim.core.Linkable} protocol and adds edges that
+ * define a ring lattice.
+ * Note that no connections are removed, they are only added. So it can be used
+ * in combination with other initializers.
+ * @see  GraphFactory#wireRingLattice
+ */
+public class WireRingLattice extends WireGraph {
+
+// --------------------------------------------------------------------------
+// Parameters
+// --------------------------------------------------------------------------
+
+/**
+ * The "lattice parameter" of the graph. The out-degree of the graph is equal to
+ * 2k. See {@link GraphFactory#wireRingLattice} (to which this parameter is
+ * passed) for further details.
+ * @config
+ */
+private static final String PAR_K = "k";
+
+// --------------------------------------------------------------------------
+// Fields
+// --------------------------------------------------------------------------
+
+/**
+ */
+private final int k;
+
+// --------------------------------------------------------------------------
+// Initialization
+// --------------------------------------------------------------------------
+
+/**
+ * Standard constructor that reads the configuration parameters.
+ * Invoked by the simulation engine.
+ * @param prefix the configuration prefix for this class
+ */
+public WireRingLattice(String prefix)
+{
+       super(prefix);
+       k = Configuration.getInt(prefix + "." + PAR_K);
+}
+
+//--------------------------------------------------------------------------
+//Public methods
+//--------------------------------------------------------------------------
+
+/** calls {@link GraphFactory#wireRingLattice}. */
+public void wire(Graph g)
+{
+       GraphFactory.wireRingLattice(g, k);
+}
+
+//--------------------------------------------------------------------------
+
+}
diff --git a/contrib/psg/src/peersim/dynamics/WireScaleFreeBA.java b/contrib/psg/src/peersim/dynamics/WireScaleFreeBA.java
new file mode 100644 (file)
index 0000000..3b6ca30
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * 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.config.*;
+import peersim.core.*;
+import peersim.graph.*;
+
+/**
+* This class contains the implementation of the Barabasi-Albert model
+* of growing scale free networks. The original model is described in
+* <a href="http://arxiv.org/abs/cond-mat/0106096">http://arxiv.org/abs/cond-mat/0106096</a>. It also contains the option of building
+* a directed network, in which case the model is a variation of the BA model
+* described in <a href="http://arxiv.org/pdf/cond-mat/0408391">
+http://arxiv.org/pdf/cond-mat/0408391</a>. In both cases, the number of the
+* initial set of nodes is the same as the degree parameter, and no links are
+* added. The first added node is connected to all of the initial nodes,
+* and after that the BA model is used normally.
+* @see GraphFactory#wireScaleFreeBA
+*/
+public class WireScaleFreeBA extends WireGraph {
+
+
+// ================ constants ============================================
+// =======================================================================
+
+/**
+ * The number of edges added to each new node (apart from those forming the 
+ * initial network).
+ * Passed to {@link GraphFactory#wireScaleFreeBA}.
+ * @config
+ */
+private static final String PAR_DEGREE = "k";
+
+
+// =================== fields ============================================
+// =======================================================================
+
+/** Parameter of the BA model. */
+private int k;
+
+// ===================== initialization ==================================
+// =======================================================================
+
+/**
+ * Standard constructor that reads the configuration parameters.
+ * Invoked by the simulation engine.
+ * @param prefix the configuration prefix for this class
+*/
+public WireScaleFreeBA(String prefix)
+{
+       super(prefix);
+       k = Configuration.getInt(prefix + "." + PAR_DEGREE);
+}
+
+
+// ======================== methods =======================================
+// ========================================================================
+
+
+/** calls {@link GraphFactory#wireScaleFreeBA}.*/
+public void wire(Graph g) {
+       
+       GraphFactory.wireScaleFreeBA(g,k,CommonState.r );
+}
+
+}
+
diff --git a/contrib/psg/src/peersim/dynamics/WireScaleFreeDM.java b/contrib/psg/src/peersim/dynamics/WireScaleFreeDM.java
new file mode 100644 (file)
index 0000000..06ae973
--- /dev/null
@@ -0,0 +1,126 @@
+/*
+ * 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.graph.Graph;
+import peersim.config.*;
+import peersim.core.*;
+
+/**
+ * Wires a scale free graph using a method described in
+ * <a href="http://xxx.lanl.gov/abs/cond-mat/0106144">this paper</a>.
+ * It is an incremental technique, where the new nodes are connected to
+ * the two ends of an edge that is already in the network.
+ * This model always wires undirected links.
+ */
+public class WireScaleFreeDM extends WireGraph {
+
+
+//--------------------------------------------------------------------------
+// Constants
+//--------------------------------------------------------------------------
+
+/** 
+ * The number of edges added to each new
+ * node (apart from those forming the initial network) is twice this
+ * value.
+ * @config
+ */
+private static final String PAR_EDGES = "k";
+
+
+//--------------------------------------------------------------------------
+// Fields
+//--------------------------------------------------------------------------
+
+
+/** The number of edges created for a new node is 2*k. */      
+private final int k;
+
+
+//--------------------------------------------------------------------------
+// Constructor
+//--------------------------------------------------------------------------
+
+/**
+ * Standard constructor that reads the configuration parameters.
+ * Invoked by the simulation engine.
+ * @param prefix the configuration prefix for this class
+ */
+public WireScaleFreeDM(String prefix)
+{
+       super(prefix);
+       k = Configuration.getInt(prefix + "." + PAR_EDGES);
+}
+
+
+//--------------------------------------------------------------------------
+// Methods
+//--------------------------------------------------------------------------
+
+/**
+ * Wires a scale free graph using a method described in
+ * <a href="http://xxx.lanl.gov/abs/cond-mat/0106144">this paper</a>.
+ * It is an incremental technique, where the new nodes are connected to
+ * the two ends of an edge that is already in the network.
+ * This model always wires undirected links.
+*/
+public void wire(Graph g) {
+
+       int nodes=g.size();
+       int[] links = new int[4*k*nodes];
+
+       // Initial number of nodes connected as a clique
+       int clique = (k > 3 ? k : 3);
+
+       // Add initial edges, to form a clique
+       int len=0;
+       for (int i=0; i < clique; i++)
+       for (int j=0; j < clique; j++)
+       {
+               if (i != j)
+               {
+                       g.setEdge(i,j);
+                       g.setEdge(j,i);
+                       links[len*2] = i;
+                       links[len*2+1] = j;
+                       len++;
+               }
+       }
+
+       for (int i=clique; i < nodes; i++)
+       for (int l=0; l < k; l++)
+       {
+               int edge = CommonState.r.nextInt(len);
+               int m = links[edge*2];
+               int j = links[edge*2+1];
+               g.setEdge(i, m);
+               g.setEdge(m, i);
+               g.setEdge(j, m);
+               g.setEdge(m, j);
+               links[len*2] = i;
+               links[len*2+1] = m;
+               len++;
+               links[len*2] = j;
+               links[len*2+1] = m;
+               len++;
+       }
+}
+               
+}
diff --git a/contrib/psg/src/peersim/dynamics/WireStar.java b/contrib/psg/src/peersim/dynamics/WireStar.java
new file mode 100644 (file)
index 0000000..0f11b64
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * 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.graph.*;
+
+/**
+ * Takes a {@link peersim.core.Linkable} protocol and adds connection
+ * which for a star
+ * topology. No connections are removed, they are only added. So it can be used
+ * in combination with other initializers.
+ * @see GraphFactory#wireStar
+ */
+public class WireStar extends WireGraph {
+
+// ===================== initialization ==============================
+// ===================================================================
+
+/**
+ * Standard constructor that reads the configuration parameters.
+ * Invoked by the simulation engine.
+ * @param prefix the configuration prefix for this class
+ */
+public WireStar(String prefix) { super(prefix); }
+
+// ===================== public methods ==============================
+// ===================================================================
+
+
+/** Calls {@link GraphFactory#wireStar}.*/
+public void wire(Graph g) {
+       
+       GraphFactory.wireStar(g);
+}
+
+
+}
+
diff --git a/contrib/psg/src/peersim/dynamics/WireWS.java b/contrib/psg/src/peersim/dynamics/WireWS.java
new file mode 100644 (file)
index 0000000..65cefed
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+ * 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.graph.*;
+import peersim.core.*;
+import peersim.config.Configuration;
+
+/**
+* Takes a {@link Linkable} protocol and adds connections following the
+* small-world model of Watts and Strogatz. Note that no
+* connections are removed, they are only added. So it can be used in
+* combination with other initializers.
+* @see GraphFactory#wireWS
+*/
+public class WireWS extends WireGraph {
+
+
+// ========================= fields =================================
+// ==================================================================
+
+/**
+ * The beta parameter of a Watts-Strogatz graph represents the probability for a
+ * node to be re-wired.
+ * Passed to {@link GraphFactory#wireWS}.
+ * @config
+ */
+private static final String PAR_BETA = "beta";
+
+/**
+ * The degree of the graph. See {@link GraphFactory#wireRingLattice}.
+ * Passed to {@link GraphFactory#wireWS}.
+ * @config
+ */
+private static final String PAR_DEGREE = "k";
+
+/**
+ * The degree of the regular graph
+ */
+private final int k;
+
+/**
+ * The degree of the regular graph
+ */
+private final double beta;
+
+
+// ==================== initialization ==============================
+//===================================================================
+
+
+/**
+ * Standard constructor that reads the configuration parameters.
+ * Invoked by the simulation engine.
+ * @param prefix the configuration prefix for this class
+ */
+public WireWS(String prefix) {
+
+       super(prefix);
+       k = Configuration.getInt(prefix+"."+PAR_DEGREE);
+       beta = Configuration.getDouble(prefix+"."+PAR_BETA);
+}
+
+
+// ===================== public methods ==============================
+// ===================================================================
+
+
+/** calls {@link GraphFactory#wireWS}.*/
+public void wire(Graph g) {
+
+       GraphFactory.wireWS(g,k,beta,CommonState.r);
+}
+
+}
+
diff --git a/contrib/psg/src/peersim/edsim/CDScheduler.java b/contrib/psg/src/peersim/edsim/CDScheduler.java
new file mode 100644 (file)
index 0000000..f864ff5
--- /dev/null
@@ -0,0 +1,213 @@
+/*
+ * 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.*;
+import peersim.cdsim.CDProtocol;
+import peersim.config.*;
+import peersim.dynamics.NodeInitializer;
+
+/**
+ * Schedules the first execution of the cycle based protocol instances in the
+ * event driven engine. It implements {@link Control} but it will most often be
+ * invoked only once for each protocol as an initializer, since the scheduled
+ * events schedule themselves for the consecutive executions (see
+ * {@link NextCycleEvent}).
+ *
+ * <p>
+ * 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.
+        * <p>
+        * 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 (file)
index 0000000..8c12d3a
--- /dev/null
@@ -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 (file)
index 0000000..60c83a2
--- /dev/null
@@ -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 (file)
index 0000000..e56d021
--- /dev/null
@@ -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}.
+ * <p>
+ * 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.
+ * <p>
+ * 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.
+ * <p>
+ * 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.
+ * <p>
+ * 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.
+ * <p>
+ * {@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.
+ * <p>
+ * 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 (file)
index 0000000..eb123ac
--- /dev/null
@@ -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<rep; i++) {
+               if (values1[i] != values2[i])
+                       System.out.print("+");
+       }
+}
+*/
+
+} // END Heap
diff --git a/contrib/psg/src/peersim/edsim/NextCycleEvent.java b/contrib/psg/src/peersim/edsim/NextCycleEvent.java
new file mode 100644 (file)
index 0000000..18de9d5
--- /dev/null
@@ -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.edsim;
+
+import peersim.core.*;
+import peersim.cdsim.CDProtocol;
+
+/**
+ * This class is used to wrap a {@link CDProtocol} instance into an event so
+ * that it can be used in the event based simulation engine. This class is
+ * responsible for calling {@link CDProtocol#nextCycle} and also to schedule the
+ * consecutive cycle. In the configuration of an event driven simulation
+ * {@link CDProtocol}s can be configured using {@link CDScheduler}, which places
+ * appropriate instances of this events in the queue.
+ *
+ * <p>
+ * Note that reimplementing method {@link #nextDelay} of this class allows for
+ * arbitrary scheduling, including adaptively changing or irregular cycle
+ * lengths, etc.
+ *
+ * @see CDScheduler
+ * @see CDProtocol
+ */
+public class NextCycleEvent implements Cloneable {
+
+       // =============================== initialization ======================
+       // =====================================================================
+
+       /**
+        * Reads configuration to initialize the object. Extending classes should
+        * have a constructor with the same signature, often as simple as
+        * <code>super(n)</code>.
+        */
+       public NextCycleEvent(String n) {
+       }
+
+       // --------------------------------------------------------------------
+
+       /**
+        * Returns a clone of the object. Overriding this method is necessary and
+        * typically is as simple as <code>return super.clone()</code>. In general,
+        * always use <code>super.clone()</code> 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 (file)
index 0000000..5525768
--- /dev/null
@@ -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 <tt>maxPriority()+1</tt> 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 (file)
index 0000000..b74a4f4
--- /dev/null
@@ -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*<code>step</code> (exclusive)
+* (expected value is therefore <code>step</code>).
+*/
+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 (file)
index 0000000..dbc5edb
--- /dev/null
@@ -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 <code>step</code> 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 <code>step</code>. 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 (file)
index 0000000..5fba52d
--- /dev/null
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="ASCII"?>
+<jsp:Model xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:jsp="http://www.eclipse.org/MoDisco/JSP/0.1.incubation/jsp"/>
diff --git a/contrib/psg/src/peersim/edsim/edsim_kdm.xmi b/contrib/psg/src/peersim/edsim/edsim_kdm.xmi
new file mode 100644 (file)
index 0000000..db34498
--- /dev/null
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="ASCII"?>
+<kdm:Segment xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:kdm="http://www.eclipse.org/MoDisco/kdm/kdm" xmlns:source="http://www.eclipse.org/MoDisco/kdm/source">
+  <model xsi:type="source:InventoryModel" name="edsim">
+    <inventoryElement xsi:type="source:Directory" name="edsim" path="/home/imb/Bureau/kbaati/pseclipse/work/PSG/src/peersim/edsim">
+      <inventoryElement xsi:type="source:SourceFile" name="RandNextCycle.java" path="/home/imb/Bureau/kbaati/pseclipse/work/PSG/src/peersim/edsim/RandNextCycle.java"/>
+      <inventoryElement xsi:type="source:SourceFile" name="RegRandNextCycle.java" path="/home/imb/Bureau/kbaati/pseclipse/work/PSG/src/peersim/edsim/RegRandNextCycle.java"/>
+      <inventoryElement xsi:type="source:SourceFile" name="Heap.java" path="/home/imb/Bureau/kbaati/pseclipse/work/PSG/src/peersim/edsim/Heap.java"/>
+      <inventoryElement xsi:type="source:SourceFile" name="ControlEvent.java" path="/home/imb/Bureau/kbaati/pseclipse/work/PSG/src/peersim/edsim/ControlEvent.java"/>
+      <inventoryElement xsi:type="source:SourceFile" name="EDSimulator.java" path="/home/imb/Bureau/kbaati/pseclipse/work/PSG/src/peersim/edsim/EDSimulator.java"/>
+      <inventoryElement xsi:type="source:SourceFile" name="CDScheduler.java" path="/home/imb/Bureau/kbaati/pseclipse/work/PSG/src/peersim/edsim/CDScheduler.java"/>
+      <inventoryElement xsi:type="source:SourceFile" name="PriorityQ.java" path="/home/imb/Bureau/kbaati/pseclipse/work/PSG/src/peersim/edsim/PriorityQ.java"/>
+      <inventoryElement xsi:type="source:SourceFile" name="NextCycleEvent.java" path="/home/imb/Bureau/kbaati/pseclipse/work/PSG/src/peersim/edsim/NextCycleEvent.java"/>
+      <inventoryElement xsi:type="source:SourceFile" name="EDProtocol.java" path="/home/imb/Bureau/kbaati/pseclipse/work/PSG/src/peersim/edsim/EDProtocol.java"/>
+    </inventoryElement>
+  </model>
+</kdm:Segment>
diff --git a/contrib/psg/src/peersim/graph/BitMatrixGraph.java b/contrib/psg/src/peersim/graph/BitMatrixGraph.java
new file mode 100644 (file)
index 0000000..7e88fec
--- /dev/null
@@ -0,0 +1,160 @@
+/*
+ * 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.graph;
+
+import java.util.*;
+
+/**
+* This class implements a graph which uses a bitmatrix as inner representation
+* of edges.
+*/
+public class BitMatrixGraph implements Graph {
+
+
+// ====================== private fileds ========================
+// ==============================================================
+
+private final List<BitSet> sets;
+
+private final boolean directed;
+
+// ====================== public constructors ===================
+// ==============================================================
+
+
+/**
+* Constructs a directed graph with the given number of nodes.
+* The graph has no edges initially. The graph is directed.
+* @param n size of graph
+*/
+public BitMatrixGraph( int n ) {
+
+       this(n,true);
+}
+
+// ---------------------------------------------------------------
+
+/**
+* Constructs an graph with the given number of nodes.
+* The graph has no edges initially.
+* @param n size of graph
+* @param directed if true graph is directed
+*/
+public BitMatrixGraph( int n, boolean directed ) {
+
+       sets = new ArrayList<BitSet>(n);
+       for(int i=0; i<n; ++i) sets.add(new BitSet());
+       this.directed = directed;
+}
+
+
+// ======================= Graph implementations ================
+// ==============================================================
+
+
+public boolean isEdge(int i, int j) {
+       
+       return sets.get(i).get(j);
+}
+
+// ---------------------------------------------------------------
+
+public Collection<Integer> getNeighbours(int i) {
+       
+       Set<Integer> result = new HashSet<Integer>();
+       BitSet neighb = sets.get(i);
+       final int max = size();
+       for(int j=0; j<max; ++j)
+       {
+               if( neighb.get(j) ) result.add(j);
+       }
+
+       return Collections.unmodifiableCollection(result);
+}
+
+// ---------------------------------------------------------------
+
+/** Returns null always */
+public Object getNode(int i) { return null; }
+       
+// ---------------------------------------------------------------
+
+/**
+* Returns null always. 
+*/
+public Object getEdge(int i, int j) { return null; }
+
+// ---------------------------------------------------------------
+
+public int size() { return sets.size(); }
+
+// --------------------------------------------------------------------
+       
+public boolean directed() { return directed; }
+
+// --------------------------------------------------------------------
+
+public boolean setEdge(int i, int j) {
+
+       if( i > size() || j > size() || i<0 || j<0 ) throw new
+               IndexOutOfBoundsException();
+
+       BitSet neighb = sets.get(i);
+       boolean old = neighb.get(j);
+       neighb.set(j);
+       
+       if( !old && !directed )
+       {
+               neighb = sets.get(j);
+               neighb.set(i);
+       }
+       
+       return !old;
+}
+
+// --------------------------------------------------------------------
+
+public boolean clearEdge(int i, int j) {
+
+       if( i > size() || j > size() || i<0 || j<0 ) throw new
+               IndexOutOfBoundsException();
+
+       BitSet neighb = sets.get(i);
+       boolean old = neighb.get(j);
+       neighb.clear(j);
+       
+       if( old && !directed )
+       {
+               neighb = sets.get(i);
+               neighb.clear(j);
+       }
+       
+       return old;
+}
+
+// --------------------------------------------------------------------
+
+public int degree(int i) {
+
+       BitSet neighb = sets.get(i);
+       return neighb.cardinality(); // only from jdk 1.4
+}
+
+}
+
diff --git a/contrib/psg/src/peersim/graph/ConstUndirGraph.java b/contrib/psg/src/peersim/graph/ConstUndirGraph.java
new file mode 100644 (file)
index 0000000..3aac06f
--- /dev/null
@@ -0,0 +1,185 @@
+/*
+ * 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.graph;
+
+import java.util.*;
+
+/**
+* This class is an adaptor making any Graph an undirected graph
+* by making its edges bidirectional. The graph to be made undirected
+* is passed to the constructor. Only the reference is stored.
+* However, at construction time the incoming edges are stored
+* for each node, so if the graph
+* passed to the constructor changes over time then
+* methods {@link #getNeighbours(int)} and {@link #degree(int)}
+* become inconsistent (but only those).
+* The upside of this inconvenience is that {@link #getNeighbours} will have
+* constant time complexity.
+* @see UndirectedGraph
+*/
+public class ConstUndirGraph implements Graph {
+
+
+// ====================== private fileds ========================
+// ==============================================================
+
+
+protected final Graph g;
+
+protected final List<Integer>[] in;
+
+// ====================== public constructors ===================
+// ==============================================================
+
+/**
+* Initialization based on given graph. Stores the graph and if necessary
+* (if the graph is directed) searches for the incoming edges and stores
+* them too. The given graph is stored by reference (not cloned) so it should
+* not be modified while this object is in use.
+*/
+public ConstUndirGraph( Graph g ) {
+
+       this.g = g;
+       if( !g.directed() )
+       {
+               in = null;
+       }
+       else
+       {
+               in = new List[g.size()];
+       }
+       
+       initGraph();
+}
+       
+// --------------------------------------------------------------
+
+/** Finds and stores incoming edges */
+protected void initGraph() {
+
+       final int max = g.size();
+       for(int i=0; i<max; ++i) in[i] = new ArrayList<Integer>();
+       for(int i=0; i<max; ++i)
+       {
+               for(Integer j:g.getNeighbours(i))
+               {
+                       if( ! g.isEdge(j,i) ) in[j].add(i);
+               }
+       }
+}
+
+
+// ======================= Graph implementations ================
+// ==============================================================
+
+
+public boolean isEdge(int i, int j) {
+       
+       return g.isEdge(i,j) || g.isEdge(j,i);
+}
+
+// ---------------------------------------------------------------
+
+/**
+* Uses sets as collection so does not support multiple edges now, even if
+* the underlying directed graph does.
+*/
+public Collection<Integer> getNeighbours(int i) {
+       
+       List<Integer> result = new ArrayList<Integer>();
+       result.addAll(g.getNeighbours(i));
+       if( in != null ) result.addAll(in[i]);
+       return Collections.unmodifiableCollection(result);
+}
+
+// ---------------------------------------------------------------
+
+/** Returns the node from the underlying graph */
+public Object getNode(int i) { return g.getNode(i); }
+       
+// ---------------------------------------------------------------
+
+/**
+* If there is an (i,j) edge, returns that, otherwise if there is a (j,i)
+* edge, returns that, otherwise returns null.
+*/
+public Object getEdge(int i, int j) {
+       
+       if( g.isEdge(i,j) ) return g.getEdge(i,j);
+       if( g.isEdge(j,i) ) return g.getEdge(j,i);
+       return null;
+}
+
+// ---------------------------------------------------------------
+
+public int size() { return g.size(); }
+
+// --------------------------------------------------------------------
+       
+public boolean directed() { return false; }
+
+// --------------------------------------------------------------------
+
+/** not supported */
+public boolean setEdge( int i, int j ) {
+       
+       throw new UnsupportedOperationException();
+}
+
+// ---------------------------------------------------------------
+
+/** not supported */
+public boolean clearEdge( int i, int j ) {
+       
+       throw new UnsupportedOperationException();
+}
+
+// ---------------------------------------------------------------
+
+public int degree(int i) { return g.degree(i)+(in==null?0:in[i].size()); }
+
+// ---------------------------------------------------------------
+/*
+public static void main( String[] args ) {
+
+       Graph net = new BitMatrixGraph(20);
+       GraphFactory.wireKOut(net,5,new Random());
+       ConstUndirGraph ug = new ConstUndirGraph(net);
+       for(int i=0; i<net.size(); ++i)
+               System.err.println(
+                       i+" "+net.getNeighbours(i)+" "+net.degree(i));
+       System.err.println("============");
+       for(int i=0; i<ug.size(); ++i)
+               System.err.println(i+" "+ug.getNeighbours(i)+" "+ug.degree(i));
+       System.err.println("============");
+       for(int i=0; i<ug.size(); ++i)
+               System.err.println(i+" "+ug.in[i]);
+       for(int i=0; i<ug.size(); ++i)
+       {
+               for(int j=0; j<ug.size(); ++j)
+                       System.err.print(ug.isEdge(i,j)?"W ":"+ ");
+               System.err.println();
+       }
+
+       GraphIO.writeUCINET_DL(net,System.out);
+       GraphIO.writeUCINET_DL(ug,System.out);
+}
+*/
+}
+
diff --git a/contrib/psg/src/peersim/graph/FastUndirGraph.java b/contrib/psg/src/peersim/graph/FastUndirGraph.java
new file mode 100644 (file)
index 0000000..9f5de5e
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ * 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.
+ *
+ */
+
+/*
+ * Created on Jan 30, 2005 by Spyros Voulgaris
+ *
+ */
+package peersim.graph;
+
+import java.util.ArrayList;
+import java.util.BitSet;
+
+/**
+* Speeds up {@link ConstUndirGraph#isEdge} by storing the links in an
+* adjacency matrix (in fact in a triangle).
+* Its memory consumption is huge but it's much faster if the isEdge method
+* of the original underlying graph is slow.
+*/
+public class FastUndirGraph extends ConstUndirGraph
+{
+
+private BitSet[] triangle;
+
+
+// ======================= initializarion ==========================
+// =================================================================
+
+
+/** Calls super constructor */
+public FastUndirGraph(Graph graph)
+{
+       super(graph);
+}
+
+// -----------------------------------------------------------------
+
+protected void initGraph()
+{
+       final int max = g.size();
+       triangle = new BitSet[max];
+       for (int i=0; i<max; ++i)
+       {
+               in[i] = new ArrayList<Integer>();
+               triangle[i] = new BitSet(i);
+       }
+
+       for(int i=0; i<max; ++i)
+       {
+               for(Integer out:g.getNeighbours(i))
+               {
+                       int j=out.intValue();
+                       if( ! g.isEdge(j,i) )
+                               in[j].add(i);
+                       // But always add the link to the triangle
+                       if (i>j) // make sure i>j
+                               triangle[i].set(j);
+                       else
+                               triangle[j].set(i);
+               }
+       }
+}
+
+
+// ============================ Graph functions ====================
+// =================================================================
+
+
+public boolean isEdge(int i, int j)
+{
+       // make sure i>j
+       if (i<j)
+       {
+               int ii=i;
+               i=j;
+               j=ii;
+       }
+       return triangle[i].get(j);
+}
+}
+
diff --git a/contrib/psg/src/peersim/graph/Graph.java b/contrib/psg/src/peersim/graph/Graph.java
new file mode 100644 (file)
index 0000000..70a2142
--- /dev/null
@@ -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.graph;
+
+import java.util.Collection;
+
+/**
+* A general graph interface. It follows the following model:
+* the graph has n nodes which are indexed from 0 to n-1.
+* The parameters of operators refer to indices only.
+* Implementations might return objects that represent the
+* nodes or edges, although this is not required.
+*
+* Undirected graphs are modelled by the interface as directed graphs in which
+* every edge (i,j) has a corresponding reverse edge (j,i).
+*/
+public interface Graph {
+
+       /**
+       * Returns true if there is a directed edge between node i
+       * and node j.
+       */
+       boolean isEdge(int i, int j);
+
+       /**
+       * Returns a collection view to all outgoing edges from
+       * i. The collection should ideally be unmodifiable.
+       * In any case, modifying the returned collection is not safe and
+       * may result in unspecified behavior.
+       */
+       Collection<Integer> getNeighbours(int i);
+
+       /**
+       * Returns the node object associated with the index. Optional
+       * operation.
+       */
+       Object getNode(int i);
+       
+       /**
+       * Returns the edge object associated with the index. Optional
+       * operation.
+       */
+       Object getEdge(int i, int j);
+
+       /**
+       * The number of nodes in the graph.
+       */
+       int size();
+
+       /**
+       * Returns true if the graph is directed otherwise false.
+       */
+       boolean directed();
+
+       /**
+       * Sets given edge, returns true if it did not exist before.
+       * If the graph is
+       * undirected, sets the edge (j,i) as well. Optional operation.
+       */
+       public boolean setEdge(int i, int j);
+
+       /**
+       * Removes given edge, returns true if it existed before. If the graph is
+       * undirected, removes the edge (j,i) as well. Optional operation.
+       */
+       public boolean clearEdge(int i, int j);
+
+       /**
+       * Returns the degree of the given node. If the graph is directed,
+       * returns out degree.
+       */
+       public int degree(int i);
+}
diff --git a/contrib/psg/src/peersim/graph/GraphAlgorithms.java b/contrib/psg/src/peersim/graph/GraphAlgorithms.java
new file mode 100644 (file)
index 0000000..6bbb351
--- /dev/null
@@ -0,0 +1,379 @@
+/*
+ * 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.graph;
+
+import java.util.*;
+
+/**
+* Implements graph algorithms. The current implementation is NOT thread
+* safe. Some algorithms are not static, many times the result of an
+* algorithm can be read from non-static fields.
+*/
+public class GraphAlgorithms {
+
+// =================== public fields ==================================
+// ====================================================================
+
+/** output of some algorithms is passed here */
+public int[] root = null;
+private Stack<Integer> stack = new Stack<Integer>();
+private int counter=0;
+
+private Graph g=null;
+
+public final static int WHITE=0;
+public final static int GREY=1;
+public final static int BLACK=2;
+
+/** output of some algorithms is passed here */
+public int[] color = null;
+
+/** output of some algorithms is passed here */
+public Set<Integer> cluster = null;
+
+/** output of some algorithms is passed here */
+public int[] d = null;
+
+// =================== private methods ================================
+// ====================================================================
+
+
+/**
+* Collects nodes accessible from node "from" using depth-first search.
+* Works on the array {@link #color} which must be of the same length as
+* the size of the graph, and must contain values according to the
+* following semantics: 
+* WHITE (0): not seen yet, GREY (1): currently worked upon. BLACK
+* (other than 0 or 1): finished.
+* If a negative color is met, it is saved in the {@link #cluster} set
+* and is treated as black. This can be used to check if the currently
+* visited cluster is weakly connected to another cluster.
+* On exit no nodes are GREY.
+* The result is the modified array {@link #color} and the modified set
+* {@link #cluster}.
+*/
+private void dfs( int from ) {
+
+       color[from]=GREY;
+
+       for(int j:g.getNeighbours(from))
+       {
+               if( color[j]==WHITE )
+               {
+                       dfs(j);
+               }
+               else
+               {
+                       if( color[j]<0 ) cluster.add(color[j]);
+               }
+       }
+
+       color[from]=BLACK;
+}
+
+// --------------------------------------------------------------------
+
+/**
+* Collects nodes accessible from node "from" using breadth-first search.
+* Its parameters and side-effects are identical to those of dfs.
+* In addition, it stores the shortest distances from "from" in {@link #d},
+* if it is not null. On return, <code>d[i]</code> contains the length of
+* the shortest path from "from" to "i", if such a path exists, or it is
+* unchanged (ie the original value of <code>d[i]</code> is kept,
+* whatever that was.
+* <code>d</code> must either be long enough or null.
+*/
+private void bfs( int from ) {
+
+       List<Integer> q = new LinkedList<Integer>();
+       int u, du;
+       
+       q.add(from);
+       q.add(0);
+       if( d != null ) d[from] = 0;
+
+       color[from]=GREY;
+
+       while( ! q.isEmpty() )
+       {
+               u = q.remove(0).intValue();
+               du = q.remove(0).intValue();
+               
+               for(int j:g.getNeighbours(u))
+               {
+                       if( color[j]==WHITE )
+                       {
+                               color[j]=GREY;
+                               
+                               q.add(j);
+                               q.add(du+1);
+                               if( d != null ) d[j] = du+1;
+                       }
+                       else
+                       {
+                               if( color[j]<0 )
+                                       cluster.add(color[j]);
+                       }
+               }
+               color[u]=BLACK;
+       }
+}
+
+// --------------------------------------------------------------------
+
+/** The recursive part of the Tarjan algorithm. */
+private void tarjanVisit(int i) {
+
+       color[i]=counter++;
+       root[i]=i;
+       stack.push(i);
+       
+       for(int j:g.getNeighbours(i))
+       {
+               if( color[j]==WHITE )
+               {
+                       tarjanVisit(j);
+               }
+               if( color[j]>0 && color[root[j]]<color[root[i]] )
+               // inComponent is false and have to update root
+               {
+                       root[i]=root[j];
+               }
+       }
+
+       int j;
+       if(root[i]==i) //this node is the root of its cluster
+       {
+               do
+               {
+                       j=stack.pop();
+                       color[j]=-color[j];
+                       root[j]=i;
+               }
+               while(j!=i);
+       }
+}
+
+// =================== public methods ================================
+// ====================================================================
+
+/** Returns the weakly connected cluster indexes with size as a value.
+* Cluster membership can be seen from the content of the array {@link #color};
+* each node has the cluster index as color. The cluster indexes carry no
+* information; we guarantee only that different clusters have different indexes.
+*/
+public Map weaklyConnectedClusters( Graph g ) {
+
+       this.g=g;
+       if( cluster == null ) cluster = new HashSet<Integer>();
+       if( color==null || color.length<g.size() ) color = new int[g.size()];
+
+       // cluster numbers are negative integers
+       int i, j, actCluster=0;
+       for(i=0; i<g.size(); ++i) color[i]=WHITE;
+       for(i=0; i<g.size(); ++i)
+       {
+               if( color[i]==WHITE )
+               {
+                       cluster.clear();
+                       bfs(i); // dfs is recursive, for large graphs not ok
+                       --actCluster;
+                       for(j=0; j<g.size(); ++j)
+                       {
+                               if( color[j] == BLACK ||
+                                               cluster.contains(color[j]) )
+                                       color[j] = actCluster;
+                       }
+               }
+       }
+
+       Hashtable<Integer,Integer> ht = new Hashtable<Integer,Integer>();
+       for(j=0; j<g.size(); ++j)
+       {
+               Integer num = ht.get(color[j]);
+               if( num == null ) ht.put(color[j],Integer.valueOf(1));
+               else ht.put(color[j],num+1);
+       }
+       
+       return ht;
+}
+
+// --------------------------------------------------------------------
+
+/**
+* In <code>{@link #d}[j]</code> returns the length of the shortest path between
+* i and j. The value -1 indicates that j is not accessible from i.
+*/
+public void dist( Graph g, int i ) {
+
+       this.g=g;
+       if( d==null || d.length<g.size() ) d = new int[g.size()];
+       if( color==null || color.length<g.size() ) color = new int[g.size()];
+       
+       for(int j=0; j<g.size(); ++j)
+       {
+               color[j]=WHITE;
+               d[j] = -1;
+       }
+       
+       bfs(i);
+}
+
+// --------------------------------------------------------------------
+
+/**
+* Calculates the clustering coefficient for the given node in the given
+* graph. The clustering coefficient is the number of edges between
+* the neighbours of i divided by the number of possible edges.
+* If the graph is directed, an exception is thrown.
+* If the number of neighbours is 1, returns 1. For zero neighbours
+* returns NAN.
+* @throws IllegalArgumentException if g is directed
+*/
+public static double clustering( Graph g, int i ) {
+
+       if( g.directed() ) throw new IllegalArgumentException(
+               "graph is directed");
+               
+       Object[] n = g.getNeighbours(i).toArray();
+       
+       if( n.length==1 ) return 1.0;
+       
+       int edges = 0;
+       
+       for(int j=0; j<n.length; ++j)
+       for(int k=j+1; k<n.length; ++k)
+               if( g.isEdge((Integer)n[j],(Integer)n[k]) ) ++edges;
+
+       return ((edges*2.0)/n.length)/(n.length-1);
+}
+
+// --------------------------------------------------------------------
+
+/**
+* Performs anti-entropy epidemic multicasting from node 0.
+* As a result the number of nodes that have been reached in cycle i
+* is put into <code>b[i]</code>.
+* The number of cycles performed is determined by <code>b.length</code>.
+* In each cycle each node contacts a random neighbour and exchanges
+* information. The simulation is generational: when a node contacts a neighbor
+* in cycle i, it sees their state as in cycle i-1, besides, all nodes update
+* their state at the same time point, synchronously.
+*/
+public static void multicast( Graph g, int[] b, Random r ) {
+
+       int c1[] = new int[g.size()];
+       int c2[] = new int[g.size()];
+       for(int i=0; i<c1.length; ++i) c2[i]=c1[i]=WHITE;
+       c2[0]=c1[0]=BLACK;
+       Collection<Integer> neighbours=null;
+       int black=1;
+       
+       int k=0;
+       for(; k<b.length || black<g.size(); ++k)
+       {
+               for(int i=0; i<c2.length; ++i)
+               {
+                       neighbours=g.getNeighbours(i);
+                       Iterator<Integer> it=neighbours.iterator();
+                       for(int j=r.nextInt(neighbours.size()); j>0; --j)
+                               it.next();
+                       int randn = it.next();
+                       
+                       // push pull exchane with random neighbour
+                       if( c1[i]==BLACK ) //c2[i] is black too
+                       {
+                               if(c2[randn]==WHITE) ++black;
+                               c2[randn]=BLACK;
+                       }
+                       else if( c1[randn]==BLACK )
+                       {
+                               if(c2[i]==WHITE) ++black;
+                               c2[i]=BLACK;
+                       }
+               }
+               System.arraycopy(c2,0,c1,0,c1.length);
+               b[k]=black;
+       }
+       
+       for(; k<b.length; ++k) b[k]=g.size();
+}
+
+// --------------------------------------------------------------------
+
+/**
+* Performs flooding from given node.
+* As a result <code>b[i]</code> contains the number of nodes
+* reached in exactly i steps, and always <code>b[0]=1</code>.
+* If the maximal distance from k is lower than <code>b.length</code>,
+* then the remaining elements of b are zero.
+*/
+public void flooding( Graph g, int[] b, int k ) {
+
+       dist(g, k);
+
+       for(int i=0; i<b.length; ++i) b[i]=0;
+       for(int i=0; i<d.length; ++i)
+       {
+               if( d[i] >= 0 && d[i] < b.length ) b[d[i]]++;
+       }
+}
+
+// --------------------------------------------------------------------
+
+/** Returns the strongly connected cluster roots with size as a value.
+* Cluster membership can be seen from the content of the array {@link #root};
+* each node has the root of the strongly connected cluster it belongs to.
+* A word of caution: for large graphs that have a large diameter and that
+* are strongly connected (such as large rings) you can get stack overflow
+* because of the large depth of recursion.
+*/
+//XXX implement a non-recursive version ASAP!!!
+public Map tarjan( Graph g ) {
+       
+       this.g=g;
+       stack.clear();
+       if( root==null || root.length<g.size() ) root = new int[g.size()];
+       if( color==null || color.length<g.size() ) color = new int[g.size()];
+       for( int i=0; i<g.size(); ++i) color[i]=WHITE;
+       counter = 1;
+       
+       // color is WHITE (0): not visited
+       // not WHITE, positive (c>1): visited as the c-th node
+       // color is negative (c<1): inComponent true
+       for(int i=0; i<g.size(); ++i)
+       {
+               if( color[i]==WHITE ) tarjanVisit(i);
+       }
+       for( int i=0; i<g.size(); ++i) color[i]=0;
+       for( int i=0; i<g.size(); ++i) color[root[i]]++;
+       Hashtable<Integer,Integer> ht = new Hashtable<Integer,Integer>();
+       for(int j=0; j<g.size(); ++j)
+       {
+               if(color[j]>0)
+               {
+                       ht.put(j,color[j]);
+               }
+       }
+       
+       return ht;
+}
+
+}
+
diff --git a/contrib/psg/src/peersim/graph/GraphFactory.java b/contrib/psg/src/peersim/graph/GraphFactory.java
new file mode 100644 (file)
index 0000000..81857cc
--- /dev/null
@@ -0,0 +1,300 @@
+/*
+ * 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.graph;
+
+import java.util.*;
+
+/**
+* Contains static methods for wiring certain kinds of graphs. The general
+* contract of all methods is that they accept any graph and add edges
+* as specified in the documentation.
+*/
+public class GraphFactory {
+
+/** Disable instance construction */
+private GraphFactory() {}
+
+// ===================== public static methods ======================
+// ==================================================================
+
+/**
+* Wires a ring lattice.
+* The added connections are defined as follows. If k is even, links to
+* i-k/2, i-k/2+1, ..., i+k/2 are added (but not to i), thus adding an
+* equal number of predecessors and successors.
+* If k is odd, then we add one more successors than predecessors.
+* For example, for k=4: 2 predecessors, 2 successors.
+* For k=5: 2 predecessors, 3 successors.
+* For k=1: each node is linked only to its successor.
+* All values are understood mod n to make the lattice circular, where n is the
+* number of nodes in g.
+* @param g the graph to be wired
+* @param k lattice parameter
+* @return returns g for convenience
+*/
+public static Graph wireRingLattice(Graph g, int k) {
+       
+       final int n = g.size();
+
+       int pred = k/2;
+       int succ = k-pred;
+
+       for(int i=0; i<n; ++i)
+       for(int j=-pred; j<=succ; ++j)
+       {
+               if( j==0 ) continue;
+               final int v = (i+j+n)%n;
+               g.setEdge(i,v);
+       }
+       return g;
+}
+
+// -------------------------------------------------------------------
+
+/**
+* Watts-Strogatz model. A bit modified though: by default assumes a directed
+* graph. This means that directed
+* links are re-wired, and the undirected edges in the original (undirected)
+* lattice are modeled
+* by double directed links pointing in opposite directions. Rewiring is done
+* with replacement, so the possibility of wiring two links to the same target
+* is positive (though very small).
+* <p>
+* Note that it is possible to pass an undirected graph as a parameter. In that
+* case the output is the directed graph produced by the method, converted to
+* an undirected graph by dropping directionality of the edges. This graph is
+* still not from the original undirected WS model though.
+* @param g the graph to be wired
+* @param k lattice parameter: this is the out-degree of a node in the
+* ring lattice before rewiring
+* @param p the probability of rewiring each 
+* @param r source of randomness
+* @return returns g for convenience
+*/
+public static Graph wireWS( Graph g, int k, double p, Random r ) {
+//XXX unintuitive to call it WS due to the slight mods
+       final int n = g.size();
+       for(int i=0; i<n; ++i)
+       for(int j=-k/2; j<=k/2; ++j)
+       {
+               if( j==0 ) continue;
+               int newedge = (i+j+n)%n;
+               if( r.nextDouble() < p )
+               {
+                       newedge = r.nextInt(n-1);
+                       if( newedge >= i ) newedge++; // random _other_ node
+               }
+               g.setEdge(i,newedge);
+       }
+       return g;
+}
+
+// -------------------------------------------------------------------
+
+/**
+* Random graph. Generates randomly k directed edges out of each node.
+* The neighbors
+* (edge targets) are chosen randomly without replacement from the nodes of the
+* graph other than the source node (i.e. no loop edge is added).
+* If k is larger than N-1 (where N is the number of nodes) then k is set to
+* be N-1 and a complete graph is returned.
+* @param g the graph to be wired
+* @param k samples to be drawn for each node
+* @param r source of randomness
+* @return returns g for convenience
+*/
+public static Graph wireKOut( Graph g, int k, Random r ) {
+
+       final int n = g.size();
+       if( n < 2 ) return g;
+       if( n <= k ) k=n-1;
+       int[] nodes = new int[n];
+       for(int i=0; i<nodes.length; ++i) nodes[i]=i;
+       for(int i=0; i<n; ++i)
+       {
+               int j=0;
+               while(j<k)
+               {
+                       int newedge = j+r.nextInt(n-j);
+                       int tmp = nodes[j];
+                       nodes[j] = nodes[newedge];
+                       nodes[newedge] = tmp;
+                       if( nodes[j] != i )
+                       {
+                               g.setEdge(i,nodes[j]);
+                               j++;
+                       }
+               }
+       }
+       return g;
+}
+
+// -------------------------------------------------------------------
+
+/**
+* A sink star.
+* Wires a sink star topology adding a link to 0 from all other nodes.
+* @param g the graph to be wired
+* @return returns g for convenience
+*/
+public static Graph wireStar( Graph g ) {
+
+       final int n = g.size();
+       for(int i=1; i<n; ++i) g.setEdge(i,0);
+       return g;
+}
+
+// -------------------------------------------------------------------
+
+/**
+* A regular rooted tree.
+* Wires a regular rooted tree. The root is 0, it has links to 1,...,k.
+* In general, node i has links to i*k+1,...,i*k+k.
+* @param g the graph to be wired
+* @param k the number of outgoing links of nodes in the tree (except
+* leaves that have zero out-links, and exactly one node that might have
+* less than k).
+* @return returns g for convenience
+*/
+public static Graph wireRegRootedTree( Graph g, int k ) {
+
+       if( k==0 ) return g;
+       final int n = g.size();
+       int i=0; // node we wire
+       int j=1; // next free node to link to
+       while(j<n)
+       {
+               for(int l=0; l<k && j<n; ++l,++j) g.setEdge(i,j);
+               ++i;
+       }
+       return g;
+}
+
+// -------------------------------------------------------------------
+
+/**
+* A hypercube.
+* Wires a hypercube.
+* For a node i the following links are added: i xor 2^0, i xor 2^1, etc.
+* this define a log(graphsize) dimensional hypercube (if the log is an
+* integer).
+* @param g the graph to be wired
+* @return returns g for convenience
+*/
+public static Graph wireHypercube( Graph g ) {
+
+       final int n = g.size();
+       if(n<=1) return g;
+       final int highestone = Integer.highestOneBit(n-1); // not zero
+       for(int i=0; i<n; ++i)
+       {
+               int mask = highestone;
+               while(mask>0)
+               {
+                       int j = i^mask;
+                       if(j<n) g.setEdge(i,j);
+                       mask = mask >> 1;
+               }
+               
+       }
+       return g;
+}
+
+// -------------------------------------------------------------------
+
+/**
+* This contains the implementation of the Barabasi-Albert model
+* of growing scale free networks. The original model is described in
+* <a href="http://arxiv.org/abs/cond-mat/0106096">
+http://arxiv.org/abs/cond-mat/0106096</a>.
+* It also works if the graph is directed, in which case the model is a
+* variation of the BA model
+* described in <a href="http://arxiv.org/pdf/cond-mat/0408391">
+http://arxiv.org/pdf/cond-mat/0408391</a>. In both cases, the number of the
+* initial set of nodes is the same as the degree parameter, and no links are
+* added. The first added node is connected to all of the initial nodes,
+* and after that the BA model is used normally.
+* @param k the number of edges that are generated for each new node, also
+* the number of initial nodes (that have no edges).
+* @param r the randomness to be used
+* @return returns g for convenience
+*/
+public static Graph wireScaleFreeBA( Graph g, int k, Random r ) {
+
+       final int nodes = g.size();
+       if( nodes <= k ) return g;
+       
+       // edge i has ends (ends[2*i],ends[2*i+1])
+       int[] ends = new int[2*k*(nodes-k)];
+       
+       // Add initial edges from k to 0,1,...,k-1
+       for(int i=0; i < k; i++)
+       {
+               g.setEdge(k,i);
+               ends[2*i]=k;
+               ends[2*i+1]=i;
+       }
+       
+       int len = 2*k; // edges drawn so far is len/2
+       for(int i=k+1; i < nodes; i++) // over the remaining nodes
+       {
+               for (int j=0; j < k; j++) // over the new edges
+               {
+                       int target;
+                       do
+                       {
+                               target = ends[r.nextInt(len)]; 
+                               int m=0;
+                               while( m<j && ends[len+2*m+1]!=target) ++m;
+                               if(m==j) break;
+                               // we don't check in the graph because
+                               // this wire method should accept graphs
+                               // that already have edges.
+                       }
+                       while(true);
+                       g.setEdge(i,target);
+                       ends[len+2*j]=i;
+                       ends[len+2*j+1]=target;
+               }
+               len += 2*k;
+       }
+
+       return g;
+}
+
+// -------------------------------------------------------------------
+/*
+public static void main(String[] pars) {
+       
+       int n = Integer.parseInt(pars[0]);
+       //int k = Integer.parseInt(pars[1]);
+       Graph g = new BitMatrixGraph(n);
+       
+       //wireWS(g,20,.1,new Random());
+       //GraphIO.writeChaco(new UndirectedGraph(g),System.out);
+       
+       //wireScaleFreeBA(g,3,new Random());
+       //wireKOut(g,k,new Random());
+       //wireRegRootedTree(g,k);
+       wireHypercube(g);
+       GraphIO.writeNeighborList(g,System.out);
+}
+*/
+}
+
diff --git a/contrib/psg/src/peersim/graph/GraphIO.java b/contrib/psg/src/peersim/graph/GraphIO.java
new file mode 100644 (file)
index 0000000..9d928d3
--- /dev/null
@@ -0,0 +1,295 @@
+/*
+ * 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.graph;
+
+import java.util.*;
+import java.io.*;
+
+/**
+* Implements static methods to load and write graphs.
+*/
+public class GraphIO {
+private GraphIO() {}
+
+
+// ================== public static methods =========================
+// ==================================================================
+
+
+/**
+* Prints graph in edge list format. Each line contains exactly two
+* node IDs separated by whitespace.
+*/
+public static void writeEdgeList( Graph g, PrintStream out ) {
+
+       for(int i=0; i<g.size(); ++i)
+       {
+               Iterator it=g.getNeighbours(i).iterator();
+               while(it.hasNext())
+               {
+                       out.println(i+" "+it.next());
+               }
+       }
+}
+
+// ------------------------------------------------------------------
+
+/**
+* Prints graph in neighbor list format. Each line starts with the
+* id of a node followed by the ids of its neighbors separated by space.
+*/
+public static void writeNeighborList( Graph g, PrintStream out ) {
+
+       out.println("# "+g.size());
+       
+       for(int i=0; i<g.size(); ++i)
+       {
+               out.print(i+" ");
+               Iterator it=g.getNeighbours(i).iterator();
+               while(it.hasNext())
+               {
+                       out.print(it.next()+" ");
+               }
+               out.println();
+       }
+}
+
+// ------------------------------------------------------------------
+
+/**
+* Saves the given graph to
+* the given stream in DOT format. Good for the graphviz package.
+*/
+public static void writeDOT( Graph g, PrintStream out ) {
+
+       out.println((g.directed()?"digraph":"graph")+" {");
+       
+       for(int i=0; i<g.size(); ++i)
+       {
+               Iterator<Integer> it=g.getNeighbours(i).iterator();
+               while(it.hasNext())
+               {
+                       final int j = it.next();
+                       if(g.directed())
+                               out.println(i+" -> "+j+";");
+                       else if( i<=j )
+                               out.println(i+" -- "+j+";");
+               }
+       }
+       
+       out.println("}");
+}
+
+// ------------------------------------------------------------------
+
+/**
+* Saves the given graph to
+* the given stream in GML format.
+*/
+public static void writeGML( Graph g, PrintStream out ) {
+
+       out.println("graph [ directed "+(g.directed()?"1":"0"));
+       
+       for(int i=0; i<g.size(); ++i)
+               out.println("node [ id "+i+" ]");
+       
+       for(int i=0; i<g.size(); ++i)
+       {
+               Iterator it=g.getNeighbours(i).iterator();
+               while(it.hasNext())
+               {
+                       out.println(
+                               "edge [ source "+i+" target "+it.next()+" ]");
+               }
+       }
+       
+       out.println("]");
+}
+
+// --------------------------------------------------------------------
+
+/**
+* Saves the given graph to
+* the given stream to be read by NETMETER. It should be ok also for Pajek.
+*/
+public static void writeNetmeter( Graph g, PrintStream out ) {
+
+       out.println("*Vertices "+g.size());
+       for(int i=0; i<g.size(); ++i)
+               out.println((i+1)+" \""+(i+1)+"\"");
+       
+       out.println("*Arcs");
+       for(int i=0; i<g.size(); ++i)
+       {
+               Iterator it=g.getNeighbours(i).iterator();
+               while(it.hasNext())
+               {
+                       out.println((i+1)+" "+
+                               (((Integer)it.next()).intValue()+1)+" 1");
+               }
+       }
+       out.println("*Edges");
+}
+
+// --------------------------------------------------------------------
+
+/**
+* Saves the given graph to
+* the given stream in UCINET DL nodelist format.
+*/
+public static void writeUCINET_DL( Graph g, PrintStream out ) {
+
+       out.println("DL\nN="+g.size()+"\nFORMAT=NODELIST\nDATA:");
+       
+       for(int i=0; i<g.size(); ++i)
+       {
+               out.print(" " + (i+1));
+               Iterator it=g.getNeighbours(i).iterator();
+               while(it.hasNext())
+               {
+                       out.print(" "+(((Integer)it.next()).intValue()+1));
+               }
+               out.println();
+       }
+       out.println();
+}
+
+// --------------------------------------------------------------------
+
+/**
+* Saves the given graph to
+* the given stream in UCINET DL matrix format.
+*/
+public static void writeUCINET_DLMatrix( Graph g, PrintStream out ) {
+
+       out.println("DL\nN="+g.size()+"\nDATA:");
+       
+       for(int i=0; i<g.size(); ++i)
+       {
+               BitSet bs = new BitSet(g.size());
+               Iterator it=g.getNeighbours(i).iterator();
+               while(it.hasNext())
+               {
+                       bs.set( ((Integer)it.next()).intValue() );
+               }
+               for(int j=0; j<g.size(); ++j)
+               {
+                       out.print(bs.get(j)?" 1":" 0");
+               }
+               out.println();
+       }
+       out.println();
+}
+
+// --------------------------------------------------------------------
+
+/**
+* Saves the given graph to
+* the given stream in Chaco format. We need to output the number of edges
+* so they have to be counted first which might not be very efficient.
+* Note that this format is designed for undirected graphs only.
+*/
+public static void writeChaco( Graph g, PrintStream out ) {
+
+       if( g.directed() ) System.err.println(
+               "warning: you're saving a directed graph in Chaco format");
+       
+       long edges = 0;
+       for(int i=0; i<g.size(); ++i) edges += g.getNeighbours(i).size();
+       
+       out.println( g.size() + " " + edges/2 );
+       
+       for(int i=0; i<g.size(); ++i)
+       {
+               Iterator it=g.getNeighbours(i).iterator();
+               while(it.hasNext())
+               {
+                       out.print((((Integer)it.next()).intValue()+1)+" ");
+               }
+               out.println();
+       }
+       
+       out.println();
+}
+
+// -------------------------------------------------------------------
+
+/**
+* Read a graph in newscast graph format.
+* The format depends on mode, the parameter.
+* The file begins with the three byte latin 1 coded "NCG" string followed
+* by the int MODE which is the
+* given parameter. The formats are the following as a function of mode:
+* <ul>
+* <li> 1: Begins with cacheSize in binary format (int), followed by the
+*     numberOfNodes (int), and then a continuous series of exactly
+*     numberOfNodes records, where a record describes a node's
+*     neighbours and their timestamps.
+*     A record is a series of exactly cacheSize (int,long) pairs where
+*     the int is the node id, and the long is the timestamp.
+*     Node id-s start from 1. Node id 0 means no node and used if the parent
+*     node has less that cacheSize nodes.</li>
+* </ul>
+* @param file Filename to read
+* @param direction If 0, the original directionality is preserved, if 1,
+* than each edge is reversed, if 2 then directionality is dropped and the
+* returned graph will be undirected.
+*/
+public static Graph readNewscastGraph( String file, int direction )
+throws IOException {
+       
+       NeighbourListGraph gr = new NeighbourListGraph( direction != 2 );
+       FileInputStream fis = new FileInputStream(file);
+       DataInputStream dis = new DataInputStream(fis);
+
+       dis.readByte();
+       dis.readByte();
+       dis.readByte();
+       
+       final int MODE = dis.readInt();
+       if( MODE != 1 ) throw new IOException("Unknown mode "+MODE);
+       
+       final int CACHESIZE = dis.readInt(); 
+       final int GRAPHSIZE = dis.readInt(); 
+       
+//System.out.println("header: "+MODE+" "+CACHESIZE+" "+GRAPHSIZE);
+       
+       for(int i=1; i<=GRAPHSIZE; ++i)
+       {
+               int iind = gr.addNode(i);
+               
+               for(int j=0; j<CACHESIZE; ++j)
+               {
+                       int a = dis.readInt();
+                       dis.readLong();
+                       
+                       int agentIndex = gr.addNode(a);
+                       if( direction == 0 ) gr.setEdge(iind,agentIndex);
+                       else gr.setEdge(agentIndex,iind);
+               }
+       }
+       
+       dis.close();
+
+       return gr;
+}
+
+
+}
+
diff --git a/contrib/psg/src/peersim/graph/NeighbourListGraph.java b/contrib/psg/src/peersim/graph/NeighbourListGraph.java
new file mode 100644 (file)
index 0000000..50b3c97
--- /dev/null
@@ -0,0 +1,173 @@
+/*
+ * 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.graph;
+
+import java.util.*;
+
+/**
+* Implements a graph which uses the neighbour list representation.
+* No multiple edges are allowed. The implementation also supports the
+* growing of the graph. This is very useful when the number of nodes is
+* not known in advance or when we construct a graph reading a file.
+*/
+public class NeighbourListGraph implements Graph, java.io.Serializable {
+
+// =================== private fields ============================
+// ===============================================================
+
+/** Contains the objects associated with the node indeces.*/
+private final ArrayList<Object> nodes;
+
+/**
+* Contains the indices of the nodes. The vector "nodes" contains this
+* information implicitly but this way we can find indexes in log time at
+* the cost of memory (node that the edge lists typically use much more memory
+* than this anyway). Note that the nodes vector is still necessary to
+* provide constant access to nodes based on indexes.
+*/
+private final HashMap<Object,Integer> nodeindex;
+
+/** Contains sets of node indexes. If "nodes" is not null, indices are 
+* defined by "nodes", otherwise they correspond to 0,1,... */
+private final ArrayList<Set<Integer>> neighbors;
+
+/** Indicates if the graph is directed. */
+private final boolean directed;
+
+// =================== public constructors ======================
+// ===============================================================
+
+/**
+* Constructs an empty graph. That is, the graph has zero nodes, but any
+* number of nodes and edges can be added later.
+* @param directed if true the graph will be directed
+*/
+public NeighbourListGraph( boolean directed ) {
+
+       nodes = new ArrayList<Object>(1000);    
+       neighbors = new ArrayList<Set<Integer>>(1000);
+       nodeindex = new HashMap<Object,Integer>(1000);
+       this.directed = directed;
+}
+
+// ---------------------------------------------------------------
+
+/**
+* Constructs a graph with a fixed size without edges. If the graph is
+* constructed this way, it is not possible to associate objects to nodes,
+* nor it is possible to grow the graph using {@link #addNode}.
+* @param directed if true the graph will be directed
+*/
+public NeighbourListGraph( int size, boolean directed ) {
+
+       nodes = null;
+       neighbors = new ArrayList<Set<Integer>>(size);
+       for(int i=0; i<size; ++i) neighbors.add(new HashSet<Integer>());
+       nodeindex = null;
+       this.directed = directed;
+}
+
+// =================== public methods =============================
+// ================================================================
+
+/**
+* If the given object is not associated with a node yet, adds a new
+* node. Returns the index of the node. If the graph was constructed to have
+* a specific size, it is not possible to add nodes and therefore calling
+* this method will throw an exception.
+* @throws NullPointerException if the size was specified at construction time.
+*/
+public int addNode( Object o ) {
+
+       Integer index = nodeindex.get(o);
+       if( index == null )
+       {
+               index = nodes.size();
+               nodes.add(o);
+               neighbors.add(new HashSet<Integer>());
+               nodeindex.put(o,index);
+       }
+
+       return index;
+}
+
+
+// =================== graph implementations ======================
+// ================================================================
+
+
+public boolean setEdge( int i, int j ) {
+       
+       boolean ret = neighbors.get(i).add(j);
+       if( ret && !directed ) neighbors.get(j).add(i);
+       return ret;
+}
+
+// ---------------------------------------------------------------
+
+public boolean clearEdge( int i, int j ) {
+       
+       boolean ret = neighbors.get(i).remove(j);
+       if( ret && !directed ) neighbors.get(j).remove(i);
+       return ret;
+}
+
+// ---------------------------------------------------------------
+
+public boolean isEdge(int i, int j) {
+       
+       return neighbors.get(i).contains(j);
+}
+
+// ---------------------------------------------------------------
+
+public Collection<Integer> getNeighbours(int i) {
+       
+       return Collections.unmodifiableCollection(neighbors.get(i));
+}
+
+// ---------------------------------------------------------------
+
+/** If the graph was gradually grown using {@link #addNode}, returns the
+* object associated with the node, otherwise null */
+public Object getNode(int i) { return (nodes==null?null:nodes.get(i)); }
+       
+// ---------------------------------------------------------------
+
+/**
+* Returns null always. 
+*/
+public Object getEdge(int i, int j) { return null; }
+
+// ---------------------------------------------------------------
+
+public int size() { return neighbors.size(); }
+
+// --------------------------------------------------------------------
+       
+public boolean directed() { return directed; }
+
+// --------------------------------------------------------------------
+
+public int degree(int i) { return neighbors.get(i).size(); }
+}
+
+
+
+
diff --git a/contrib/psg/src/peersim/graph/PrefixSubGraph.java b/contrib/psg/src/peersim/graph/PrefixSubGraph.java
new file mode 100644 (file)
index 0000000..5098316
--- /dev/null
@@ -0,0 +1,158 @@
+/*
+ * 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.graph;
+
+import java.util.*;
+
+/**
+* This class is an adaptor for representing special subgraphs of any graph.
+* It can represent the subgraphs spanned by the nodes 0,...,i where
+* i is less than or equal to n-1, the last node of the original graph.
+* The underlying graph is stored by reference. This means that if the
+* graph changes, then these changes will be reflected by this class as well.
+* Besides, the size of the prefix can be changed at will at any time
+* using {@link #setSize}.
+*/
+public class PrefixSubGraph implements Graph {
+
+
+// ====================== private fileds ========================
+// ==============================================================
+
+
+private final Graph g;
+
+/** The graph represents the subgraph defined by nodes 0,...,prefSize */
+private int prefSize;
+
+
+// ====================== public constructors ===================
+// ==============================================================
+
+
+/**
+* Constructs an initially max size subgraph of g. That is, the subgraph will
+* contain all nodes.
+*/
+public PrefixSubGraph( Graph g ) {
+
+       this.g = g;
+       prefSize = g.size();
+}
+
+
+// ======================= Graph implementations ================
+// ==============================================================
+
+
+public boolean isEdge(int i, int j) {
+       
+       if( i<0 || i>=prefSize ) throw new IndexOutOfBoundsException();
+       if( j<0 || j>=prefSize ) throw new IndexOutOfBoundsException();
+       return g.isEdge(i,j);
+}
+
+// ---------------------------------------------------------------
+
+public Collection<Integer> getNeighbours(int i) {
+       
+       if( i<0 || i>=prefSize ) throw new IndexOutOfBoundsException();
+       
+       List<Integer> result = new LinkedList<Integer>();
+       for(Integer j:g.getNeighbours(i))
+       {
+               if( j < prefSize ) result.add(j);
+       }
+
+       return Collections.unmodifiableCollection(result);
+}
+
+// ---------------------------------------------------------------
+
+public Object getNode(int i) {
+
+       if( i<0 || i>=prefSize ) throw new IndexOutOfBoundsException();
+       return g.getNode(i);
+}
+       
+// ---------------------------------------------------------------
+
+/**
+* Returns the edge in the original graph if both i and j are smaller than
+* size().
+*/
+public Object getEdge(int i, int j) {
+       
+       if( isEdge(i,j) ) return g.getEdge(i,j);
+       return null;
+}
+
+// --------------------------------------------------------------------
+
+public int size() { return prefSize; }
+
+// --------------------------------------------------------------------
+       
+public boolean directed() { return g.directed(); }
+
+// --------------------------------------------------------------------
+
+/** not supported */
+public boolean setEdge( int i, int j ) {
+       
+       throw new UnsupportedOperationException();
+}
+
+// ---------------------------------------------------------------
+
+/** not supported */
+public boolean clearEdge( int i, int j ) {
+       
+       throw new UnsupportedOperationException();
+}
+
+// ---------------------------------------------------------------
+
+public int degree(int i) {
+
+       if( i<0 || i>=prefSize ) throw new IndexOutOfBoundsException();
+       return g.degree(i);
+}
+       
+
+// ================= public functions =================================
+// ====================================================================
+
+
+/**
+* Sets the size of the subgraph. If i is negative, it is changed to 0 and
+* if it is larger than the underlying graph size, it is changed to the
+* underlying graph size (set at construction time).
+* @return old size.
+*/
+public int setSize(int i) {
+       
+       int was = prefSize;
+       if( i < 0 ) i = 0;
+       if( i > g.size() ) i=g.size();
+       prefSize=i;
+       return was;
+}
+}
+
diff --git a/contrib/psg/src/peersim/graph/SubGraphEdges.java b/contrib/psg/src/peersim/graph/SubGraphEdges.java
new file mode 100644 (file)
index 0000000..bb4201f
--- /dev/null
@@ -0,0 +1,177 @@
+/*
+ * 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.graph;
+
+import java.util.*;
+
+/**
+* This class is an adaptor for representing subgraphs of any graph.
+* The subgraph is defined the following way.
+* The subgraph always contains all the nodes of the original underlying
+* graph. However, it is possible to remove edges by flagging nodes as
+* removed, in which case
+* the edges that have at least one end on those nodes are removed.
+* If the underlying graph changes after initialization, this class follows
+* the change.
+*/
+public class SubGraphEdges implements Graph {
+
+
+// ====================== private fields ========================
+// ==============================================================
+
+
+private final Graph g;
+
+private final BitSet nodes;
+
+
+// ====================== public constructors ===================
+// ==============================================================
+
+
+/**
+* Constructs an initially empty subgraph of g. That is, the subgraph will
+* contain no nodes.
+*/
+public SubGraphEdges( Graph g ) {
+
+       this.g = g;
+       nodes = new BitSet(g.size());
+}
+
+
+// ======================= Graph implementations ================
+// ==============================================================
+
+
+public boolean isEdge(int i, int j) {
+       
+       return nodes.get(i) && nodes.get(j) && g.isEdge(i,j);
+}
+
+// ---------------------------------------------------------------
+
+public Collection<Integer> getNeighbours(int i) {
+       
+       List<Integer> result = new LinkedList<Integer>();
+       if( nodes.get(i) )
+       {
+               for(Integer in:g.getNeighbours(i))
+               {
+                       if( nodes.get(in) ) result.add(in);
+               }
+       }
+
+       return Collections.unmodifiableCollection(result);
+}
+
+// ---------------------------------------------------------------
+
+public Object getNode(int i) { return g.getNode(i); }
+       
+// ---------------------------------------------------------------
+
+/**
+* If both i and j are within the node set of the subgraph and the original
+* graph has an (i,j) edge, returns that edge.
+*/
+public Object getEdge(int i, int j) {
+       
+       if( isEdge(i,j) ) return g.getEdge(i,j);
+       return null;
+}
+
+// --------------------------------------------------------------------
+
+public int size() { return g.size(); }
+
+// --------------------------------------------------------------------
+       
+public boolean directed() { return g.directed(); }
+
+// --------------------------------------------------------------------
+
+/** not supported */
+public boolean setEdge( int i, int j ) {
+       
+       throw new UnsupportedOperationException();
+}
+
+// ---------------------------------------------------------------
+
+/** not supported */
+public boolean clearEdge( int i, int j ) {
+       
+       throw new UnsupportedOperationException();
+}
+
+// ---------------------------------------------------------------
+
+public int degree(int i) {
+
+       int degree=0;
+       if( nodes.get(i) )
+       {
+               for(Integer in:g.getNeighbours(i))
+               {
+                       if( nodes.get(in) ) degree++;
+               }
+       }
+       return degree;
+}
+
+
+// ================= public functions =================================
+// ====================================================================
+
+
+/**
+* This function returns the size of the subgraph, i.e. the number of nodes
+* in the subgraph.
+*/
+public int subGraphSize() { return nodes.cardinality(); }
+
+// --------------------------------------------------------------------
+
+/**
+* Removes given node from subgraph.
+* @return true if the node was already in the subgraph otherwise false.
+*/
+public boolean removeNode(int i) {
+       
+       boolean was = nodes.get(i);
+       nodes.clear(i);
+       return was;
+}
+
+// --------------------------------------------------------------------
+
+/**
+* Adds given node to subgraph.
+* @return true if the node was already in the subgraph otherwise false.
+*/
+public boolean addNode(int i) {
+       
+       boolean was = nodes.get(i);
+       nodes.set(i);
+       return was;
+}
+}
+
diff --git a/contrib/psg/src/peersim/graph/UndirectedGraph.java b/contrib/psg/src/peersim/graph/UndirectedGraph.java
new file mode 100644 (file)
index 0000000..d229bae
--- /dev/null
@@ -0,0 +1,152 @@
+/*
+ * 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.graph;
+
+import java.util.*;
+
+/**
+* This class is an adaptor making any Graph an undirected graph
+* by making its edges bidirectional. The graph to be made undirected
+* is passed to the constructor. Only the reference is stored so
+* if the directed graph changes later, the undirected version will
+* follow that change. However, {@link #getNeighbours} has O(n) time complexity
+* (in other words, too slow for large graphs).
+* @see ConstUndirGraph
+*/
+public class UndirectedGraph implements Graph {
+
+
+// ====================== private fileds ========================
+// ==============================================================
+
+
+private final Graph g;
+
+
+// ====================== public constructors ===================
+// ==============================================================
+
+
+public UndirectedGraph( Graph g ) {
+
+       this.g = g;
+}
+
+
+// ======================= Graph implementations ================
+// ==============================================================
+
+
+public boolean isEdge(int i, int j) {
+       
+       return g.isEdge(i,j) || g.isEdge(j,i);
+}
+
+// ---------------------------------------------------------------
+
+/**
+* Uses sets as collection so does not support multiple edges now, even if
+* the underlying directed graph does.
+*/
+public Collection<Integer> getNeighbours(int i) {
+       
+       Set<Integer> result = new HashSet<Integer>();
+       result.addAll(g.getNeighbours(i));
+       final int max = g.size();
+       for(int j=0; j<max; ++j)
+       {
+               if( g.isEdge(j,i) ) result.add(j);
+       }
+
+       return Collections.unmodifiableCollection(result);
+}
+
+// ---------------------------------------------------------------
+
+public Object getNode(int i) { return g.getNode(i); }
+       
+// ---------------------------------------------------------------
+
+/**
+* If there is an (i,j) edge, returns that, otherwise if there is a (j,i)
+* edge, returns that, otherwise returns null.
+*/
+public Object getEdge(int i, int j) {
+       
+       if( g.isEdge(i,j) ) return g.getEdge(i,j);
+       if( g.isEdge(j,i) ) return g.getEdge(j,i);
+       return null;
+}
+
+// ---------------------------------------------------------------
+
+public int size() { return g.size(); }
+
+// --------------------------------------------------------------------
+       
+public boolean directed() { return false; }
+
+// --------------------------------------------------------------------
+
+/** not supported */
+public boolean setEdge( int i, int j ) {
+       
+       throw new UnsupportedOperationException();
+}
+
+// ---------------------------------------------------------------
+
+/** not supported */
+public boolean clearEdge( int i, int j ) {
+       
+       throw new UnsupportedOperationException();
+}
+
+// --------------------------------------------------------------------
+
+public int degree(int i) {
+       
+       return getNeighbours(i).size();
+}
+
+// --------------------------------------------------------------------
+/*
+public static void main( String[] args ) {
+
+       
+       Graph net = null;       
+       UndirectedGraph ug = new UndirectedGraph(net);
+       for(int i=0; i<net.size(); ++i)
+               System.err.println(i+" "+net.getNeighbours(i));
+       System.err.println("============");
+       for(int i=0; i<ug.size(); ++i)
+               System.err.println(i+" "+ug.getNeighbours(i));
+       for(int i=0; i<ug.size(); ++i)
+       {
+               for(int j=0; j<ug.size(); ++j)
+                       System.err.print(ug.isEdge(i,j)?"W ":"- ");
+               System.err.println();
+       }
+
+       GraphIO.writeGML(net,System.out);
+}
+*/
+}
+
+
diff --git a/contrib/psg/src/peersim/rangesim/ProcessHandler.java b/contrib/psg/src/peersim/rangesim/ProcessHandler.java
new file mode 100644 (file)
index 0000000..92537ec
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * 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.rangesim;
+
+public interface ProcessHandler
+{
+
+/**
+ * Stop the external process managed by this object.
+ */
+public abstract void doStop();
+
+/**
+ * Wait until the process has terminated. 
+ * @exception InterruptedException 
+ *   thrown if the wait is interrupted
+ */
+public abstract void join()
+  throws InterruptedException;
+
+}
\ No newline at end of file
diff --git a/contrib/psg/src/peersim/rangesim/ProcessManager.java b/contrib/psg/src/peersim/rangesim/ProcessManager.java
new file mode 100644 (file)
index 0000000..1ccfc79
--- /dev/null
@@ -0,0 +1,53 @@
+package peersim.rangesim;
+
+import java.util.*;
+
+/**
+ * This thread is used to kill forked processes in the case of an abnormal
+ * termination of the Java virtual machine (for example, due to a signal).
+ */
+public class ProcessManager extends Thread
+{
+
+/** The threads that must be killed */
+private List<ProcessHandler> threads;
+
+public ProcessManager()
+{
+       threads = Collections.synchronizedList(new ArrayList<ProcessHandler>());
+}
+
+public void addThread(ProcessHandler p)
+{
+       threads.add(p);
+}
+
+/**
+ * Assumes that the process manager
+ */
+public void joinAll()
+{
+       int i=0;
+       while (i < threads.size()) {
+               try {
+                       threads.get(i).join();
+                       i++;
+               } catch (InterruptedException e) {
+               }
+       }
+}
+
+
+/**
+ * Kill the child process.
+ */
+public void run()
+{
+       System.err.println("Terminating simulation.");
+       for (int i=0; i < threads.size(); i++) {
+               if (threads.get(i) != null)
+                       threads.get(i).doStop();
+       }
+}
+
+}
\ No newline at end of file
diff --git a/contrib/psg/src/peersim/rangesim/RangeSimulator.java b/contrib/psg/src/peersim/rangesim/RangeSimulator.java
new file mode 100644 (file)
index 0000000..0995bcc
--- /dev/null
@@ -0,0 +1,461 @@
+/*
+ * 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.rangesim;
+
+import java.io.*;
+import java.util.*;
+
+import peersim.*;
+import peersim.config.*;
+import peersim.core.*;
+import peersim.util.*;
+
+/**
+ * This class is the main class for the Range Simulator. A range is
+ * a collection of values <em>S</em> to be assigned to a variable 
+ * <em>v</em>. The Range Simulator invokes the standard Peersim 
+ * simulator once for each distinct value. If multiple ranges 
+ * <em>S1, S2, ..., Sn</em> are specified, the standard Peersim
+ * simulator is invoked for each element in 
+ * <em>S1 * S2 * ... * Sn</em>.  
+ * <p>  
+ * Ranges are specified with the following syntax:
+<pre>
+range.[id] [var];[range]
+</pre>
+ * where:
+ * <UL>
+ * <LI> {@value #PAR_RANGE} is the prefix for all range
+ * specifications;</LI>
+ * <LI> <code>id</code> is an identifier; since they are not referred anywhere else,
+ * consecutive numbers are a good choice for range identifiers;</LI>
+ * <LI> <code>var</code> is a variable parameter </LI>
+ * <LI> <code>range</code> describes the collection of values to be associated
+ * to <code>var</code>, whose syntax and semantics is defined in 
+ * {@link peersim.util.StringListParser}. </LI>
+ * </UL>
+ * Examples of range specifications are the following:
+<pre>
+range.0 SIZE;2^10:2^18|*2
+range.1 K;20:30
+range.2 CHURN;0.05,0.10,0.20 
+</pre>
+ * With this specification, the collection of values associated to 
+ * <code>SIZE</code> is {2^10,2^11,...,2^18}; <code>K</code> contains 
+ * {20,21,22,...,30}, while <code>CHURN</code> contains just the
+ * specified values.
+ * <p>
+ * Values can be specified as constant expressions (like 2^10, (5+10), etc.)
+ * but variables cannot be used. 
+ * <p>
+ * A separate Java virtual machine is invoked to run each of the
+ * experiments. An attempt is done to run the same JVM version as
+ * the one running the Range Simulator; if this is not possible
+ * (for example due to path problems), the command shell mechanism
+ * is used to run the first JVM version found in the path.
+ * </p>
+ * It is possible to specify options for the forked JVM using the
+ * {@value #PAR_JVM} parameter on the command line. For example,
+ * a command line like this:
+<pre>
+java peersim.rangesim.RangeSimulator config.file jvm.options=-Xmx256m
+</pre>
+ * can be used to run the forked JVM with a maximum heap of 256MB.
+ * <p>
+ * The new JVM inherits the same classpath as the JVM running the
+ * RangeSimulator. The {@value #PAR_JVM} parameter can be used to
+ * specify additional classpath specification.
+ * 
+ * @author Alberto Montresor
+ * @version $Revision: 1.11 $
+ */
+public class RangeSimulator implements ProcessHandler
+{
+
+// --------------------------------------------------------------------------
+// Configuration parameters
+// --------------------------------------------------------------------------
+
+/**
+ * This is the prefix of the config properties whose value vary during
+ * a set of experiments.
+ * @config
+ */
+private static final String PAR_RANGE = "range";
+
+/**
+ * This config property can be used to set options in the JVMs that
+ * are forked to execute experiments with different configuration
+ * parameters.
+ * @config
+ */
+public static final String PAR_JVM = "jvm.options";
+
+
+// --------------------------------------------------------------------------
+// Static variables
+// --------------------------------------------------------------------------
+
+/** Names of range parameters */
+private String[] pars;
+
+/** Values to be simulated, for each parameter */
+private String[][] values;
+
+/** The jvm options to be used when creating jvms */
+private String[] jvmoptions;
+
+/** Command line arguments */
+private String[] args;
+
+/** The current process that is executed */
+private Process p;
+
+
+// --------------------------------------------------------------------------
+// Main
+// --------------------------------------------------------------------------
+
+/**
+ * Main method of the system.
+ */
+public static void main(String[] args)
+{
+       RangeSimulator r = new RangeSimulator(args);
+       r.run();
+}
+
+//--------------------------------------------------------------------------
+// Constructor
+//--------------------------------------------------------------------------
+
+public RangeSimulator(String[] args)
+{
+
+       // Check if there are no arguments or there is an explicit --help
+       // flag; if so, print the usage of the class
+       if (args.length == 0 || args[0].equals("--help")) {
+               usage();
+               System.exit(101);
+       }
+
+       this.args = args.clone();
+
+       // Read property file
+       System.err.println("Simulator: loading configuration");
+       Properties properties = new ParsedProperties(args);
+       Configuration.setConfig(properties);
+       
+       // Read jvm options and separate them in different strings
+       String opt = Configuration.getString(PAR_JVM, null);
+       if (opt == null)
+               jvmoptions = new String[0];
+       else
+               jvmoptions = opt.split(" ");
+
+       // Parse range parameters
+       parseRanges();
+
+}
+
+/**
+ * Main method to be executed
+ */
+public void run()
+{
+       // Shutdown thread management
+       ProcessManager t = new ProcessManager();
+       t.addThread(this);
+       Runtime.getRuntime().addShutdownHook(t);
+
+       // Executes experiments; report short messages about exceptions that are
+       // handled by the configuration mechanism.
+       try {
+               doExperiments(args);
+       } catch (MissingParameterException e) {
+               Runtime.getRuntime().removeShutdownHook(t);
+               System.err.println(e + "");
+               System.exit(101);
+       } catch (IllegalParameterException e) {
+               Runtime.getRuntime().removeShutdownHook(t);
+               System.err.println(e + "");
+               System.exit(101);
+       }
+       Runtime.getRuntime().removeShutdownHook(t);
+       System.exit(0);
+}
+
+// --------------------------------------------------------------------
+
+/**
+ * Parses a collection of range specifications and returns the set of
+ * parameter that will change during the simulation and the values that
+ * will be used for those parameters.
+ */
+private void parseRanges()
+{
+       // Get ranges
+       String[] ranges = Configuration.getNames(PAR_RANGE);
+
+       // Start is the first element in which ranges are stored
+       int start;
+       
+       // If there is an explicit simulation.experiment or there are no 
+       // ranges, put an experiment range at the beginning of the values.
+       // Otherwise, just use the ranges.
+       if (Configuration.contains(Simulator.PAR_EXPS) || ranges.length == 0) {
+               pars = new String[ranges.length + 1];
+               values = new String[ranges.length + 1][];
+               pars[0] = "EXP";
+               values[0] = StringListParser.parseList("1:"
+                               + Configuration.getInt(Simulator.PAR_EXPS, 1));
+               start = 1;
+       } else {
+               pars = new String[ranges.length];
+               values = new String[ranges.length][];
+               start = 0;
+       }
+
+       for (int i = start; i < pars.length; i++) {
+               String[] array = Configuration.getString(ranges[i-start]).split(";");
+               if (array.length != 2) {
+                       throw new IllegalParameterException(ranges[i],
+                                       " should be formatted as <parameter>;<value list>");
+               }
+               pars[i] = array[0];
+               values[i] = StringListParser.parseList(array[1]);
+       }
+}
+
+// --------------------------------------------------------------------
+
+/**
+ * Selects the next set of values by incrementing the specified index
+ * array. The index array is treated as a vector of digits; the first is
+ * managed managed as a vector of digits.
+ */
+private void nextValues(int[] idx, String[][] values)
+{
+       idx[idx.length - 1]++;
+       for (int j = idx.length - 1; j > 0; j--) {
+               if (idx[j] == values[j].length) {
+                       idx[j] = 0;
+                       idx[j - 1]++;
+               }
+       }
+}
+
+// --------------------------------------------------------------------
+
+private void doExperiments(String[] args)
+{
+
+       // Configure the java parameter for exception
+       String filesep = System.getProperty("file.separator");
+       String classpath = System.getProperty("java.class.path");
+       String javapath = System.getProperty("java.home") + filesep + "bin" + filesep
+                       + "java";
+       ArrayList<String> list = new ArrayList<String>(20);
+       list.add(javapath);
+       list.add("-cp");
+       list.add(classpath);
+       
+       // Add the jvm options
+       for (int i=0; i < jvmoptions.length; i++)
+               list.add(jvmoptions[i]);
+       
+       // The class to be run in the forked JVM
+       list.add("peersim.Simulator");
+       
+       // Parameters specified on the command line
+       for (int i=0; i < args.length; i++) {
+               list.add(args[i]);
+       }
+       
+       // Since multiple experiments are managed here, the value
+       // of standard variable for multiple experiments is changed to 1
+       list.add(Simulator.PAR_EXPS+"=1");
+
+       // Activate redirection to separate stdout from stderr
+       list.add(Simulator.PAR_REDIRECT+"="+TaggedOutputStream.class.getCanonicalName());
+       int startlog = list.size();
+       list.add(""); 
+       
+       // Create a placeholder for the seed
+       int startseed = list.size();
+       list.add("");
+       
+       // Create placeholders for the range parameters
+       int startpar = list.size();
+       for (int i=0; i < values.length; i++)
+               list.add("");
+               
+       // Execute with different values
+       int[] idx = new int[values.length]; // Initialized to 0
+       while (idx[0] < values[0].length) {
+
+               // Configure the argument string array
+               for (int j = 0; j < pars.length; j++) {
+                       list.set(startpar + j, pars[j] + "=" + values[j][idx[j]]);
+               }
+
+               // Fill the log placeholder
+               StringBuffer log = new StringBuffer();
+               for (int j = 0; j < pars.length; j++) {
+                       log.append(pars[j]);
+                       log.append(" ");
+                       log.append(values[j][idx[j]]);
+                       log.append(" ");
+               }
+               list.set(startlog, Simulator.PAR_REDIRECT+"."+
+                               TaggedOutputStream.PAR_RANGES+"="+log);
+
+               // Fill the seed place holder
+               long seed = CommonState.r.nextLong();
+               list.set(startseed, CommonState.PAR_SEED+"="+seed);
+
+               System.err.println("Experiment: " + log);
+               
+               executeProcess(list);
+
+               // Increment values
+               nextValues(idx, values);
+       
+       }
+}
+
+//--------------------------------------------------------------------
+
+/**
+ * Execute the "command line" represented by this String list.
+ * The first argument is the process to be executed. We try
+ * to run the same JVM as the current one. If not possible,
+ * we use the first java command found in the path.
+ */
+private void executeProcess(List<String> list)
+{
+       // Prepare the argument array for process forking
+       String[] newargs = new String[list.size()];
+
+       // Execute a new JVM
+       try {
+               ProcessBuilder pb = new ProcessBuilder(list.toArray(newargs));
+               pb.redirectErrorStream(true);
+               p = pb.start();
+       } catch (IOException e1) {
+               try {
+                       list.set(0, "java");
+                       ProcessBuilder pb = new ProcessBuilder(list.toArray(newargs));
+                       pb.redirectErrorStream(true);
+                       p = pb.start();
+               } catch (IOException e2) {
+                       System.err.println("Unable to launch a Java virtual machine");
+                       System.exit(1);
+               }
+       }
+
+       // Read the output from the process and redirect it to System.out
+       // and System.err.
+       BufferedReader toprint = new BufferedReader(new InputStreamReader(p
+                       .getInputStream()));
+       String line;
+       while ((line = getLine(toprint)) != null) {
+               if (line.length() == 0) {
+                       System.out.println();
+               } else {
+                       int last = line.charAt(line.length()-1);
+                       if (last != TaggedOutputStream.TAG) {
+                               System.err.println(line);
+                       } else {
+                               line = line.substring(0, line.length()-1);
+                               System.out.println(line);
+                       }
+               }
+       }
+
+       // We close all the files and we destroy the process. They are not 
+       // cleaned when the process is closed. See:
+       // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4784692
+       // http://www.thescripts.com/forum/thread18019.html
+       try {
+               p.getErrorStream().close();
+               p.getInputStream().close();
+               p.getOutputStream().close();
+               p.destroy();
+       } catch (IOException e) {
+               e.printStackTrace();
+       }
+
+       // The static variable p (used also by ShutdownThread) is back to
+       // null - no process must be killed on shutdown.
+       p = null;
+       
+       
+
+}
+
+//--------------------------------------------------------------------
+
+private static String getLine(BufferedReader toprint)
+{
+       try {
+               return toprint.readLine();
+       } catch (IOException e) {
+               // If we get here, this means that the forked process has
+               // been killed by the shutdown thread. We just exit without
+         // printing this exception.
+               System.exit(1);
+               return null; // Never reached, but needed.
+       }
+}
+
+
+// --------------------------------------------------------------------
+
+private static void usage()
+{
+       System.err.println("Usage:");
+       System.err.println("  peersim.RangeSimulator <configfile> [property]*");
+}
+
+//--------------------------------------------------------------------
+
+RangeSimulator()
+{
+}
+
+/**
+ * Stop the process executing the external java virtual machine.
+ */
+public void doStop()
+{
+       if (p != null)
+               p.destroy();
+}
+
+/**
+ * Wait until the java virtual machine has terminated; it won't be
+ * used in this class, but you never know.
+ */
+public void join() throws InterruptedException
+{
+       p.waitFor();
+}
+
+}
diff --git a/contrib/psg/src/peersim/rangesim/TaggedOutputStream.java b/contrib/psg/src/peersim/rangesim/TaggedOutputStream.java
new file mode 100644 (file)
index 0000000..6288553
--- /dev/null
@@ -0,0 +1,179 @@
+/*
+ * 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.rangesim;
+
+import java.io.*;
+import java.util.*;
+
+import peersim.config.*;
+import peersim.core.*;
+
+/**
+ * This OutputStream uses an underlying stream to output
+ * data. Each line (terminated with `\n`) is augmented
+ * with a tag character. This is used to discriminate
+ * among standard error and standard output. This 
+ * feature is needed for launching new JVMs; it should
+ * not be used for other purposes. 
+ * 
+ * @author Alberto Montresor
+ * @version $Revision: 1.5 $
+ */
+public class TaggedOutputStream extends PrintStream
+{
+
+//--------------------------------------------------------------------------
+//Constants
+//--------------------------------------------------------------------------
+
+/** 
+ * This character is appended at the end of each line. 
+ */
+public static final int TAG = 1;
+
+//--------------------------------------------------------------------------
+//Parameters
+//--------------------------------------------------------------------------
+
+/**
+ * This parameter contains the string that should be printed on each 
+ * line, containing the values of the range parameters for the experiment
+ * which is being run. The full name of this configuration string is
+ * prefixed by {@value peersim.Simulator#PAR_REDIRECT}.
+ * @config
+ */
+public static final String PAR_RANGES = "ranges";
+
+/**
+ * This parameter contains the list of observers for which the string
+ * contained in parameter {@value #PAR_RANGES} should be augmented with 
+ * a "TIME &lt;t&gt;" specification regarding current time. Observers are 
+ * separated by one of this characters: ' ' - ',' - ';'.
+ * @config
+ */
+public static final String PAR_TIME = "simulation.timed-observers";
+
+
+//--------------------------------------------------------------------------
+//Fields
+//--------------------------------------------------------------------------
+
+/** Variable used to save the original System.out to simplify printing */
+private PrintStream stdout;
+
+/** Buffer used to store a single line; it can grow */
+private byte[] buffer = new byte[1024];
+
+/** Current size of the buffer */
+private int size;
+
+/** The value of the PAR_RANGES parameter */
+private final String ranges;
+
+/** The value of the PAR_TIME parameter */
+private final ArrayList<String> obstime;
+
+//--------------------------------------------------------------------------
+//Initialization
+//--------------------------------------------------------------------------
+
+
+/**
+ * Creates a tagged output stream that prints the tagged
+ * output on the specified stream.
+ */
+public TaggedOutputStream(String prefix)
+{
+       super(System.out);
+       
+       obstime = new ArrayList<String>();
+       String[] obs = Configuration.getString(PAR_TIME, "").split("[ :,]");
+       for (int i=0; i < obs.length; i++) {
+               obstime.add("control." + obs[i]);
+       }
+       ranges = Configuration.getString(prefix + "." + PAR_RANGES, "");
+       stdout = System.out;
+       size = 0;
+}
+
+//--------------------------------------------------------------------------
+//Methods
+//--------------------------------------------------------------------------
+
+// Comment inherited from interface
+@Override
+public synchronized void write(byte[] b, int off, int len)
+{
+       if (size+len > buffer.length) {
+               byte[] tmp = new byte[Math.max(buffer.length*2, size+len)];
+               System.arraycopy(buffer, 0, tmp, 0, size);
+               buffer = tmp;
+       }
+       int last = off+len;
+       for (int i=off; i < last; i++) {
+               if (b[i] == '\n') {
+                       buffer[size++] = TAG;
+                       buffer[size++] = b[i];
+                       printLine();
+               }  else {
+                       buffer[size++] = b[i];
+               }
+       }
+}
+
+// Comment inherited from interface
+@Override
+public synchronized void write(int b)
+{
+       if (size == buffer.length) {
+               byte[] tmp = new byte[buffer.length*2];
+               System.arraycopy(buffer, 0, tmp, 0, size);
+               buffer = tmp;
+       }
+       if (b == '\n') {
+               buffer[size++] = TAG;
+               buffer[size++] = (byte) b;
+               printLine();
+       }  else {
+               buffer[size++] = (byte) b;
+       }
+}
+
+/** 
+ * Actually prints a line, inserting ranges and time
+ * when needed.
+ */
+private void printLine()
+{
+       String line = new String(buffer, 0, size);
+       String[] parts = line.split(":");
+       if (parts.length == 2) {
+               stdout.print(parts[0]);
+               stdout.print(": ");
+               stdout.print(ranges);
+               if (obstime.contains(parts[0]))
+                       stdout.print(" TIME " + CommonState.getTime() + " ");
+               stdout.print(parts[1]);
+       } else {
+               stdout.print(line);
+       }
+       size = 0;
+}
+
+}
diff --git a/contrib/psg/src/peersim/reports/BallExpansion.java b/contrib/psg/src/peersim/reports/BallExpansion.java
new file mode 100644 (file)
index 0000000..b46e117
--- /dev/null
@@ -0,0 +1,159 @@
+/*
+ * 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.reports;
+
+import peersim.config.*;
+import peersim.core.*;
+import peersim.util.*;
+
+/**
+ * Control to observe the ball expansion, that is,
+ * the number of nodes that are
+ * accessible from a given node in at most 1, 2, etc steps.
+ */
+public class BallExpansion extends GraphObserver
+{
+
+// ===================== fields =======================================
+// ====================================================================
+
+/**
+ * This parameter defines the maximal distance we care about.
+ * In other words, two nodes are further away, they will not be taken
+ * into account when calculating statistics.
+ * <p>
+ * Defaults to the
+ * network size (which means all distances are taken into account).
+ * Note that this default is normally way too much; many low diameter graphs
+ * have only short distances between the nodes. Setting a short
+ * (but sufficient) distance saves memory.
+ * Also note that the <em>initial</em> network
+ * size is used if no value is given which might not be what you want if e.g. the
+ * network is growing.
+ * @config
+ */
+private static final String PAR_MAXD = "maxd";
+
+/**
+ * The number of nodes to print info about.
+ * Defaults to 1000. If larger than the current network size, then the
+ * current network size is used.
+ * @config
+ */
+private static final String PAR_N = "n";
+
+/**
+ * If defined, statistics are printed instead over the minimal path lengths. Not
+ * defined by default.
+ * @config
+ */
+private static final String PAR_STATS = "stats";
+
+private final int maxd;
+
+private final int n;
+
+private final boolean stats;
+
+/** working variable */
+private final int[] b;
+
+private final RandPermutation rp = new RandPermutation(CommonState.r);
+
+// ===================== initialization ================================
+// =====================================================================
+
+/**
+ * Standard constructor that reads the configuration parameters.
+ * Invoked by the simulation engine.
+ * @param name the configuration prefix for this class
+ */
+public BallExpansion(String name)
+{
+       super(name);
+       maxd = Configuration.getInt(name + "." + PAR_MAXD, Network.size());
+       n = Configuration.getInt(name + "." + PAR_N, 1000);
+       stats = Configuration.contains(name + "." + PAR_STATS);
+       b = new int[maxd];
+}
+
+// ====================== methods ======================================
+// =====================================================================
+
+/**
+* Prints information about ball expansion. It uses {@value #PAR_N} nodes to
+* collect statistics.
+* If parameter {@value #PAR_STATS} is defined then the output is
+* produced by {@link IncrementalStats#toString}, over the values of minimal
+* distances from the given number of nodes to all other nodes in the network.
+* If at least one node is unreachable from any selected starting node, then
+* the path length is taken as infinity and statistics are calculated
+* accordingly. In that case, {@link IncrementalStats#getMaxCount()} returns
+* the number of nodes of "infinite distance", that is, the number of
+* unreachable nodes.
+* Otherwise one line is printed for all nodes we observe, containing the
+* number of nodes at distance 1, 2, etc, separated by spaces.
+* In this output format, unreachable nodes are simply ignored, but of course
+* the sum of the numbers in one line can be used to detect partitioning if
+* necessary.
+* Finally, note that the {@value #PAR_N} nodes are not guaranteed to be the
+* same nodes over consecutive calls to this method.
+* @return always false
+*/
+public boolean execute() {
+
+       updateGraph();
+       System.out.print(name + ": ");
+       rp.reset(g.size());
+       if (stats)
+       {
+               IncrementalStats is = new IncrementalStats();
+               for (int i = 0; i < n && i < g.size(); ++i)
+               {
+                       ga.dist(g, rp.next());
+                       for (int j=0; j<g.size(); j++)
+                       {
+                               if (ga.d[j] > 0)
+                                       is.add(ga.d[j]);
+                               else if (ga.d[j] == -1)
+                                       is.add(Double.POSITIVE_INFINITY);
+                               // deliberately left ga.d[j]==0 out, as we don't
+                               // want to count trivial distance to oneself.
+                       }
+               }
+               System.out.println(is);
+       }
+       else
+       {
+               System.out.println();
+               for (int i = 0; i < n && i < g.size(); ++i)
+               {
+                       ga.flooding(g, b, rp.next());
+                       int j = 0;
+                       while (j < b.length && b[j] > 0)
+                       {
+                               System.out.print(b[j++] + " ");
+                       }
+                       System.out.println();
+               }
+       }
+       return false;
+}
+
+}
diff --git a/contrib/psg/src/peersim/reports/Clustering.java b/contrib/psg/src/peersim/reports/Clustering.java
new file mode 100644 (file)
index 0000000..38b81f7
--- /dev/null
@@ -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.reports;
+
+import peersim.config.Configuration;
+import peersim.graph.GraphAlgorithms;
+import peersim.util.IncrementalStats;
+
+/**
+ * Control to observe the clustering coefficient.
+ * @see GraphAlgorithms#clustering
+ */
+public class Clustering extends GraphObserver
+{
+
+// ===================== fields =======================================
+// ====================================================================
+
+/**
+ * The number of nodes to collect info about. Defaults to the size of the graph.
+ * @config
+ */
+private static final String PAR_N = "n";
+
+private final int n;
+
+// ===================== initialization ================================
+// =====================================================================
+
+/**
+ * Standard constructor that reads the configuration parameters.
+ * Invoked by the simulation engine.
+ * @param name the configuration prefix for this class
+ */
+public Clustering(String name)
+{
+       super(name);
+       n = Configuration.getInt(name + "." + PAR_N, Integer.MAX_VALUE);
+}
+
+// ====================== methods ======================================
+// =====================================================================
+
+/**
+* Prints information about the clustering coefficient.
+* It uses {@value #PAR_N} nodes to collect statistics.
+* The output is
+* produced by {@link IncrementalStats#toString}, over the values of
+* the clustering coefficients of the given number of nodes.
+* Clustering coefficients are calculated by {@link GraphAlgorithms#clustering}.
+* @return always false
+*/
+public boolean execute()
+{
+       IncrementalStats stats = new IncrementalStats();
+       updateGraph();
+       for (int i = 0; i < n && i < g.size(); ++i) {
+               stats.add(GraphAlgorithms.clustering(g, i));
+       }
+       System.out.println(name + ": " + stats);
+       return false;
+}
+
+}
diff --git a/contrib/psg/src/peersim/reports/ConnectivityObserver.java b/contrib/psg/src/peersim/reports/ConnectivityObserver.java
new file mode 100644 (file)
index 0000000..d23ac08
--- /dev/null
@@ -0,0 +1,125 @@
+/*
+ * 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.reports;
+
+import java.util.Iterator;
+import java.util.Map;
+import peersim.config.Configuration;
+import peersim.util.IncrementalStats;
+
+/**
+ * Reports statistics about connectivity properties of the network, such as
+ * weakly or strongly connected clusters.
+ */
+public class ConnectivityObserver extends GraphObserver
+{
+
+//--------------------------------------------------------------------------
+//Parameters
+//--------------------------------------------------------------------------
+
+/**
+ * The parameter used to request cluster size statistics instead of the usual
+ * list of clusters. Not set by default.
+ * @config
+ */
+private static final String PAR_STATS = "stats";
+
+/**
+ * Defines the types of connected clusters to discover.
+ * Possible values are
+ * <ul>
+ * <li>"wcc": weakly connected clusters</li>
+ * <li>"scc": strongly connected clusters</li>
+ * </ul>
+ * Defaults to "wcc".
+ * @config
+ */
+private static final String PAR_TYPE = "type";
+
+//--------------------------------------------------------------------------
+//Fields
+//--------------------------------------------------------------------------
+
+/** {@link #PAR_STATS} */
+private final boolean sizestats;
+
+/** {@link #PAR_TYPE} */
+private final String type;
+
+//--------------------------------------------------------------------------
+//Initialization
+//--------------------------------------------------------------------------
+
+/**
+ * Standard constructor that reads the configuration parameters.
+ * Invoked by the simulation engine.
+ * @param name the configuration prefix for this class
+ */
+public ConnectivityObserver(String name)
+{
+       super(name);
+       sizestats = Configuration.contains(name + "." + PAR_STATS);
+       type = Configuration.getString(name + "." + PAR_TYPE,"wcc");
+}
+
+//--------------------------------------------------------------------------
+//Methods
+//--------------------------------------------------------------------------
+
+/**
+* Prints information about clusters.
+* If parameter {@value #PAR_STATS} is defined then the output is
+* produced by {@link IncrementalStats#toString}, over the sizes of the
+* clusters.
+* Otherwise one line is printed that contains the string representation of
+* a map, that holds cluster IDs mapped to cluster sizes.
+* The meaning of the cluster IDs is not specified, but is printed for
+* debugging purposes.
+* @return always false
+* @see peersim.graph.GraphAlgorithms#tarjan
+* @see peersim.graph.GraphAlgorithms#weaklyConnectedClusters
+*/
+public boolean execute()
+{
+       Map clst;
+       updateGraph();
+       
+       if(type.equals("wcc"))
+               clst=ga.weaklyConnectedClusters(g);
+       else if(type.equals("scc"))
+               clst=ga.tarjan(g);
+       else
+               throw new RuntimeException(
+               "Unsupported connted cluster type '"+type+"'");
+
+       if (!sizestats) {
+               System.out.println(name + ": " + clst);
+       } else {
+               IncrementalStats stats = new IncrementalStats();
+               Iterator it = clst.values().iterator();
+               while (it.hasNext()) {
+                       stats.add(((Integer) it.next()).intValue());
+               }
+               System.out.println(name + ": " + stats);
+       }
+       return false;
+}
+
+}
diff --git a/contrib/psg/src/peersim/reports/DegreeStats.java b/contrib/psg/src/peersim/reports/DegreeStats.java
new file mode 100644 (file)
index 0000000..d6c57e6
--- /dev/null
@@ -0,0 +1,187 @@
+/*
+ * 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.reports;
+
+import peersim.config.*;
+import peersim.core.*;
+import peersim.util.*;
+
+/**
+ * Prints several statistics about the node degrees in the graph.
+ */
+public class DegreeStats extends GraphObserver
+{
+
+//--------------------------------------------------------------------------
+//Parameter
+//--------------------------------------------------------------------------
+
+/**
+ * The number of nodes to be used for sampling the degree. 
+ * Defaults to full size of the graph.
+ * @config
+ */
+private static final String PAR_N = "n";
+
+/**
+ * If defined, then the given number of nodes will be traced. That is, it is
+ * guaranteed that in each call the same nodes will be picked in the same order.
+ * If a node being traced fails, its degree will be considered 0. Not defined by
+ * default.
+ * @config
+ */
+private static final String PAR_TRACE = "trace";
+
+/**
+ * Selects a method to use when printing results. Three methods are known:
+ * "stats" will use {@link IncrementalStats#toString}. "freq" will
+ * use {@link IncrementalFreq#print}. "list" will print the
+ * degrees of the sample nodes one by one in one line, separated by spaces.
+ * Default is "stats".
+ * @config
+ */
+private static final String PAR_METHOD = "method";
+
+/**
+ * Selects the types of links to print information about. Three methods are
+ * known: "live": links pointing to live nodes, "dead": links pointing to nodes
+ * that are unavailable and "all": both dead and live links summed. "all" and
+ * "dead" require parameter {@value peersim.reports.GraphObserver#PAR_UNDIR} 
+ * to be unset (graph must be directed). Default is "live".
+ * @config
+ */
+private static final String PAR_TYPE = "linktype";
+
+//--------------------------------------------------------------------------
+//Parameter
+//--------------------------------------------------------------------------
+
+private final int n;
+
+private final boolean trace;
+
+private Node[] traced = null;
+
+private final String method;
+
+private final String type;
+
+private final RandPermutation rp = new RandPermutation(CommonState.r);
+
+private int nextnode = 0;
+
+//--------------------------------------------------------------------------
+//Initialization
+//--------------------------------------------------------------------------
+
+/**
+ * Standard constructor that reads the configuration parameters.
+ * Invoked by the simulation engine.
+ * @param name the configuration prefix for this class
+ */
+public DegreeStats(String name)
+{
+       super(name);
+       n = Configuration.getInt(name + "." + PAR_N, -1);
+       trace = Configuration.contains(name + "." + PAR_TRACE);
+       method = Configuration.getString(name + "." + PAR_METHOD, "stats");
+       type = Configuration.getString(name + "." + PAR_TYPE, "live");
+       if ((type.equals("all") || type.equals("dead")) && undir) {
+               throw new IllegalParameterException(
+                       name + "." + PAR_TYPE, " Parameter "+ name + "." +
+                       PAR_UNDIR + " must not be defined if " + name + "."
+                       + PAR_TYPE + "=" + type + ".");
+       }
+}
+
+//--------------------------------------------------------------------------
+//Methods
+//--------------------------------------------------------------------------
+
+/**
+ * Returns next node to get degree information about.
+ */
+private int nextNodeId()
+{
+       if (trace) {
+               if (traced == null) {
+                       int nn = (n < 0 ? Network.size() : n);
+                       traced = new Node[nn];
+                       for (int j = 0; j < nn; ++j)
+                               traced[j] = Network.get(j);
+               }
+               return traced[nextnode++].getIndex();
+       } else
+               return rp.next();
+}
+
+// ---------------------------------------------------------------------
+
+/**
+ * Returns degree information about next node.
+ */
+private int nextDegree()
+{
+       final int nodeid = nextNodeId();
+       if (type.equals("live")) {
+               return g.degree(nodeid);
+       } else if (type.equals("all")) {
+               return ((OverlayGraph) g).fullDegree(nodeid);
+       } else if (type.equals("dead")) {
+               return ((OverlayGraph) g).fullDegree(nodeid) - g.degree(nodeid);
+       } else
+               throw new RuntimeException(name + ": invalid type");
+}
+
+// ---------------------------------------------------------------------
+
+/**
+ * Prints statistics about node degree. The format of the output is specified
+ * by {@value #PAR_METHOD}. See also the rest of the configuration parameters.
+ * @return always false
+ */
+public boolean execute()
+{
+       updateGraph();
+       if (!trace)
+               rp.reset(g.size());
+       else
+               nextnode = 0;
+       final int nn = (n < 0 ? Network.size() : n);
+       if (method.equals("stats")) {
+               IncrementalStats stats = new IncrementalStats();
+               for (int i = 0; i < nn; ++i)
+                       stats.add(nextDegree());
+               System.out.println(name + ": " + stats);
+       } else if (method.equals("freq")) {
+               IncrementalFreq stats = new IncrementalFreq();
+               for (int i = 0; i < nn; ++i)
+                       stats.add(nextDegree());
+               stats.print(System.out);
+               System.out.println("\n\n");
+       } else if (method.equals("list")) {
+               System.out.print(name + ": ");
+               for (int i = 0; i < nn; ++i)
+                       System.out.print(nextDegree() + " ");
+               System.out.println();
+       }
+       return false;
+}
+
+}
diff --git a/contrib/psg/src/peersim/reports/GraphObserver.java b/contrib/psg/src/peersim/reports/GraphObserver.java
new file mode 100644 (file)
index 0000000..6f939ea
--- /dev/null
@@ -0,0 +1,170 @@
+/*
+ * 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.reports;
+
+import peersim.core.*;
+import peersim.config.Configuration;
+import peersim.graph.*;
+import peersim.cdsim.CDState;
+
+/**
+* Class that provides functionality for observing graphs.
+* It can efficiently create an undirected version of the graph, making sure
+* it is updated only when the simulation has advanced already, and provides
+* some common parameters.
+*/
+public abstract class GraphObserver implements Control {
+
+
+// ===================== fields =======================================
+// ====================================================================
+
+/**
+ * The protocol to operate on.
+ * @config
+ */
+private static final String PAR_PROT = "protocol";
+
+/**
+ * If defined, the undirected version of the graph will be analyzed. Not defined
+ * by default.
+ * @config
+ */
+protected static final String PAR_UNDIR = "undir";
+
+/**
+* Alias for {@value #PAR_UNDIR}.
+* @config
+*/
+private static final String PAR_UNDIR_ALT = "undirected";
+
+/**
+ * If defined, the undirected version of the graph will be stored using much
+ * more memory but observers will be in general a few times faster. As a
+ * consequence, it will not work with large graphs. Not defined by default. It
+ * is a static property, that is, it affects all graph observers that are used
+ * in a simulation. That is, it is not a parameter of any observer, the name
+ * should be specified as a standalone property.
+ * @config
+ */
+private static final String PAR_FAST = "graphobserver.fast";
+
+/** The name of this observer in the configuration */
+protected final String name;
+
+protected final int pid;
+
+protected final boolean undir;
+
+protected final GraphAlgorithms ga = new GraphAlgorithms();
+
+protected Graph g;
+
+// ---------------------------------------------------------------------
+
+private static int lastpid = -1234;
+
+private static long time = -1234;
+
+private static int phase = -1234;
+
+private static int ctime = -1234;
+
+private static Graph dirg;
+
+private static Graph undirg;
+
+private static boolean fast;
+
+/** If any instance of some extending class defines undir we need to
+maintain an undir graph. Note that the graph is stored in a static
+field so it is common to all instances. */
+private static boolean needUndir=false;
+
+// ===================== initialization ================================
+// =====================================================================
+
+
+/**
+ * Standard constructor that reads the configuration parameters.
+ * Invoked by the simulation engine.
+ * @param name the configuration prefix for this class
+ */
+protected GraphObserver(String name) {
+
+       this.name = name;
+       pid = Configuration.getPid(name+"."+PAR_PROT);
+       undir = (Configuration.contains(name + "." + PAR_UNDIR) |
+               Configuration.contains(name + "." + PAR_UNDIR_ALT));
+       GraphObserver.fast = Configuration.contains(PAR_FAST);
+       GraphObserver.needUndir = (GraphObserver.needUndir || undir);
+}
+
+
+// ====================== methods ======================================
+// =====================================================================
+
+/**
+* Sets {@link #g}.
+* It MUST be called by any implementation of {@link #execute()} before
+* doing anything else.
+* Attempts to initialize {@link #g} from a
+* pre-calculated graph stored in a static field, but first it
+* checks whether it needs to be updated.
+* If the simulation time has progressed or it was calculated for a different
+* protocol, then updates this static graph as well.
+* The purpose of this mechanism is to save the time of constructing the
+* graph if many observers are run on the same graph. Time savings can be very
+* significant if the undirected version of the same graph is observed by many
+* observers.
+*/
+protected void updateGraph() {
+       
+       if( CommonState.getTime() != GraphObserver.time ||
+           (CDState.isCD() && (CDState.getCycleT() != GraphObserver.ctime)) ||
+           CommonState.getPhase() != GraphObserver.phase ||
+           pid != GraphObserver.lastpid )
+       {
+               // we need to update the graphs
+               
+               GraphObserver.lastpid = pid;
+               GraphObserver.time = CommonState.getTime();
+               if( CDState.isCD() ) GraphObserver.ctime = CDState.getCycleT();
+               GraphObserver.phase = CommonState.getPhase();
+
+               GraphObserver.dirg = new OverlayGraph(pid);
+               if( GraphObserver.needUndir )
+               {
+                       if( fast )
+                               GraphObserver.undirg =
+                               new FastUndirGraph(GraphObserver.dirg);
+                       else
+                               GraphObserver.undirg =
+                               new ConstUndirGraph(GraphObserver.dirg);
+               }
+       }
+       
+       if( undir ) g = GraphObserver.undirg;
+       else g = GraphObserver.dirg;
+}
+
+}
+
+
+
diff --git a/contrib/psg/src/peersim/reports/GraphPrinter.java b/contrib/psg/src/peersim/reports/GraphPrinter.java
new file mode 100644 (file)
index 0000000..3317c10
--- /dev/null
@@ -0,0 +1,142 @@
+/*
+ * 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.reports;
+
+import peersim.config.Configuration;
+import peersim.graph.GraphIO;
+import peersim.util.FileNameGenerator;
+import java.io.PrintStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+/**
+* Prints the whole graph in a given format.
+*/
+public class GraphPrinter extends GraphObserver {
+
+
+// ===================== fields =======================================
+// ====================================================================
+
+/**
+* This is the prefix of the filename where the graph is saved.
+* The extension is ".graph" and after the prefix the basename contains
+* a numeric index that is incremented at each saving point.
+* If not given, the graph is dumped on the standard output.
+* @config
+*/
+private static final String PAR_BASENAME = "outf";
+
+/**
+* The name for the format of the output. Defaults to "neighborlist",
+* which is a plain dump of neighbors. The class
+* {@link peersim.dynamics.WireFromFile} can read this format.
+* Other supported formats are "chaco" to be used with Yehuda Koren's
+* Embedder, "netmeter" to be used with Sergi Valverde's netmeter and also
+* with pajek,
+* "edgelist" that dumps one (directed) node pair in each line for each edge,
+* "gml" that is a generic format of many graph tools, and "dot" that can
+* be used with the graphviz package.
+* @see GraphIO#writeEdgeList
+* @see GraphIO#writeChaco
+* @see GraphIO#writeNeighborList
+* @see GraphIO#writeNetmeter
+* @config
+*/
+private static final String PAR_FORMAT = "format";
+
+private final String baseName;
+
+private final FileNameGenerator fng;
+
+private final String format;
+
+
+// ===================== initialization ================================
+// =====================================================================
+
+
+/**
+ * Standard constructor that reads the configuration parameters.
+ * Invoked by the simulation engine.
+ * @param name the configuration prefix for this class
+ */
+public GraphPrinter(String name) {
+
+       super(name);
+       baseName = Configuration.getString(name+"."+PAR_BASENAME,null);
+       format = Configuration.getString(name+"."+PAR_FORMAT,"neighborlist");
+       if(baseName!=null) fng = new FileNameGenerator(baseName,".graph");
+       else fng = null;
+}
+
+
+// ====================== methods ======================================
+// =====================================================================
+
+
+/**
+* Saves the graph according to the specifications in the configuration.
+* @return always false
+*/
+public boolean execute() {
+try {  
+       updateGraph();
+       
+       System.out.print(name+": ");
+       
+       // initialize output streams
+       FileOutputStream fos = null;
+       PrintStream pstr = System.out;
+       if( baseName != null )
+       {
+               String fname = fng.nextCounterName();
+               fos = new FileOutputStream(fname);
+               System.out.println("writing to file "+fname);
+               pstr = new PrintStream(fos);
+       }
+       else    System.out.println();
+       
+       if( format.equals("neighborlist") )
+               GraphIO.writeNeighborList(g, pstr);
+       else if( format.equals("edgelist") )
+               GraphIO.writeEdgeList(g, pstr);
+       else if( format.equals("chaco") )
+               GraphIO.writeChaco(g, pstr);
+       else if( format.equals("netmeter") )
+               GraphIO.writeNetmeter(g, pstr);
+       else if( format.equals("gml") )
+               GraphIO.writeGML(g, pstr);
+       else if( format.equals("dot") )
+               GraphIO.writeDOT(g, pstr);
+       else
+               System.err.println(name+": unsupported format "+format);
+       
+       if( fos != null ) fos.close();
+       
+       return false;
+}
+catch( IOException e )
+{
+       throw new RuntimeException(e);
+}
+}
+
+}
+
diff --git a/contrib/psg/src/peersim/reports/GraphStats.java b/contrib/psg/src/peersim/reports/GraphStats.java
new file mode 100644 (file)
index 0000000..a57773c
--- /dev/null
@@ -0,0 +1,150 @@
+/*
+ * 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.reports;
+
+import peersim.config.Configuration;
+import peersim.graph.GraphAlgorithms;
+import peersim.util.IncrementalStats;
+
+/**
+* Prints reports on the graph like average clustering and average path length,
+* based on random sampling of the nodes.
+* In fact its functionality is a subset of the union of {@link Clustering}
+* and {@link BallExpansion}, and therefore is redundant,
+* but it is there for historical reasons.
+* @see BallExpansion
+* @see Clustering
+*/
+public class GraphStats extends GraphObserver {
+
+
+// ===================== fields =======================================
+// ====================================================================
+
+/** 
+* The number of nodes to use for
+* sampling average path length.
+* Statistics are printed over a set of node pairs.
+* To create the set of pairs, we select the given number of different nodes
+* first, and then pair all these nodes with every other node in the network.
+* If zero is given, then no statistics
+* will be printed about path length. If a negative value is given then
+* the value is the full size of the graph.
+* Defaults to zero.
+* @config
+*/
+private static final String PAR_NL = "nl";
+
+/** 
+* The number of nodes to use to sample
+* average clustering.
+* If zero is given, then no statistics
+* will be printed about clustering. If a negative value is given then
+* the value is the full size of the graph.
+* Defaults to zero.
+* @config
+*/
+private static final String PAR_NC = "nc";
+
+private final int nc;
+
+private final int nl;
+
+
+// ===================== initialization ================================
+// =====================================================================
+
+
+/**
+ * Standard constructor that reads the configuration parameters.
+ * Invoked by the simulation engine.
+ * @param name the configuration prefix for this class
+ */
+public GraphStats(String name) {
+
+       super(name);
+       nl = Configuration.getInt(name+"."+PAR_NL,0);
+       nc = Configuration.getInt(name+"."+PAR_NC,0);
+}
+
+
+// ====================== methods ======================================
+// =====================================================================
+
+/**
+* Returns statistics over minimal path length and clustering.
+* The output is the average over the set of
+* clustering coefficients of randomly selected nodes, and the
+* set of distances from randomly selected nodes to all the other nodes.
+* The output is always concatenated in one line, containing zero, one or two
+* numbers (averages) as defined by the config parameters.
+* Note that the path length between a pair of nodes can be infinite, in which
+* case the statistics will reflect this (the average will be infinite, etc).
+* See also the configuration parameters.
+* @return always false
+* @see BallExpansion
+* @see Clustering
+*/
+public boolean execute() {
+       
+       System.out.print(name+": ");
+       
+       IncrementalStats stats = new IncrementalStats();
+       updateGraph();
+       
+       if( nc != 0 )
+       {
+               stats.reset();
+               final int n = ( nc<0 ? g.size() : nc );
+               for(int i=0; i<n && i<g.size(); ++i)
+               {
+                       stats.add(GraphAlgorithms.clustering(g,i));
+               }
+               System.out.print(stats.getAverage()+" ");
+       }
+       
+       if( nl != 0 )
+       {
+               stats.reset();
+               final int n = ( nl<0 ? g.size() : nl );
+               outerloop:
+               for(int i=0; i<n && i<g.size(); ++i)
+               {
+                       ga.dist(g,i);
+                       for(int j=0; j<g.size(); ++j)
+                       {
+                               if( j==i ) continue;
+                               if (ga.d[j] == -1)
+                               {
+                                       stats.add(Double.POSITIVE_INFINITY);
+                                       break outerloop;
+                               }
+                               else
+                                       stats.add(ga.d[j]); 
+                       }
+               }
+               System.out.print(stats.getAverage());
+       }
+       
+       System.out.println();
+       return false;
+}
+
+}
+
diff --git a/contrib/psg/src/peersim/reports/MemoryObserver.java b/contrib/psg/src/peersim/reports/MemoryObserver.java
new file mode 100644 (file)
index 0000000..839108c
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * 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.reports;
+
+import peersim.core.*;
+
+/**
+ * This observer reports memory utilization (max, total and 
+ * free, as defined by <code>java.lang.Runtime</code>).
+ *
+ * @author Alberto Montresor
+ * @version $Revision: 1.1 $
+ */
+public class MemoryObserver implements Control
+{
+
+/** The runtime object to obtain memory info */
+private final static Runtime r = Runtime.getRuntime(); 
+
+/** The prefix to be printed */
+private final String prefix;
+
+/**
+ * Constructor to be instantiated in PeerSim.
+ * @param prefix
+ */
+public MemoryObserver(String prefix)
+{
+       this.prefix = prefix;
+}
+
+public boolean execute()
+{
+       System.out.println(prefix + ": max=" + r.maxMemory() + ", total=" + 
+                       r.totalMemory() + ", free=" + r.freeMemory()); 
+       return false;
+}
+
+}
diff --git a/contrib/psg/src/peersim/reports/RandRemoval.java b/contrib/psg/src/peersim/reports/RandRemoval.java
new file mode 100644 (file)
index 0000000..8872873
--- /dev/null
@@ -0,0 +1,122 @@
+/*
+ * 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.reports;
+
+import peersim.core.*;
+import peersim.config.Configuration;
+import peersim.graph.*;
+import peersim.util.IncrementalStats;
+import java.util.Map;
+import java.util.Iterator;
+
+/**
+ * It tests the network for robustness to random node removal.
+ * It does not actually remove
+ * nodes, it is only an observer, so can be applied several times during the
+ * simulation. A warning though: as a side effect it <em>may
+ * shuffle the network</em> (see {@value #PAR_N}) so if this is an issue,
+ * it should not be used,
+ * or only after the simulation has finished.
+ */
+public class RandRemoval extends GraphObserver
+{
+
+// ===================== fields =======================================
+// ====================================================================
+
+// XXX remove side effect
+/**
+ * This parameter defines the number of runs of the iterative removal procedure
+ * to get statistics. Look out: if set to a value larger than 1 then as a side
+ * effect <em>the overlay will be shuffled</em>. Defaults to 1.
+ * @config
+ */
+private static final String PAR_N = "n";
+
+private final int n;
+
+// ===================== initialization ================================
+// =====================================================================
+
+/**
+ * Standard constructor that reads the configuration parameters.
+ * Invoked by the simulation engine.
+ * @param name the configuration prefix for this class
+ */
+public RandRemoval(String name)
+{
+       super(name);
+       n = Configuration.getInt(name + "." + PAR_N, 1);
+}
+
+// ====================== methods ======================================
+// =====================================================================
+
+/**
+* Prints results of node removal tests. The following experiment is
+* repeated {@value #PAR_N} times. From the graph 50%, 51%, ..., 99% of the nodes
+* are removed at random. For all percentages it is calculated what is
+* the maximal
+* clustersize (weakly connected clusters) and the number of
+* clusters in the remaining graph.
+* These values are averaged over the experiments, and for all 50 different
+* percentage values a line is printed that contains the respective averages,
+* first the average maximal cluster size, followed by the average number
+* of clusters.
+* @return always false
+*/
+public boolean execute()
+{
+       if( n < 1 ) return false;
+       updateGraph();
+       
+       System.out.println(name + ":");
+       
+       final int size = Network.size();
+       final int steps = 50;
+       IncrementalStats[] maxClust = new IncrementalStats[steps];
+       IncrementalStats[] clustNum = new IncrementalStats[steps];
+       for (int i = 0; i < steps; ++i) {
+               maxClust[i] = new IncrementalStats();
+               clustNum[i] = new IncrementalStats();
+       }
+       for (int j = 0; j < n; ++j) {
+               PrefixSubGraph sg = new PrefixSubGraph(g);
+               IncrementalStats stats = new IncrementalStats();
+               for (int i = 0; i < steps; i++) {
+                       sg.setSize(size / 2 - i * (size / 100));
+                       Map clst = ga.weaklyConnectedClusters(sg);
+                       stats.reset();
+                       Iterator it = clst.values().iterator();
+                       while (it.hasNext()) {
+                               stats.add(((Integer) it.next()).intValue());
+                       }
+                       maxClust[i].add(stats.getMax());
+                       clustNum[i].add(clst.size());
+               }
+               if( j+1 < n ) Network.shuffle();
+       }
+       for (int i = 0; i < steps; ++i) {
+               System.out.println(maxClust[i].getAverage() + " "
+                               + clustNum[i].getAverage());
+       }
+       return false;
+}
+
+}
diff --git a/contrib/psg/src/peersim/transport/E2ENetwork.java b/contrib/psg/src/peersim/transport/E2ENetwork.java
new file mode 100644 (file)
index 0000000..a184f9a
--- /dev/null
@@ -0,0 +1,144 @@
+/*
+ * 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.transport;
+
+
+/**
+ * This static singleton emulates an underlying router network
+ * of fixed size, and stores the latency measurements for all pairs
+ * of routers.
+ *
+ * @author Alberto Montresor
+ * @version $Revision: 1.6 $
+ */
+public class E2ENetwork
+{
+
+//---------------------------------------------------------------------
+//Fields
+//---------------------------------------------------------------------
+
+/**
+ * True if latency between nodes is considered symmetric. False otherwise.
+ */
+private static boolean symm;   
+       
+/**
+ * Size of the router network. 
+ */
+private static int size;
+
+/**
+ * Latency distances between nodes.
+ */
+private static int[][] array;
+       
+//---------------------------------------------------------------------
+//Initialization
+//---------------------------------------------------------------------
+
+/** Disable instance construction */
+private E2ENetwork() {}
+
+//---------------------------------------------------------------------
+//Methods
+//---------------------------------------------------------------------
+
+/**
+ * Resets the network, by creating a triangular (if symm is true) or
+ * a rectangular (if symm is false) array of integers. Initially all
+ * latencies between any pairs are set to be 0.
+ * @param size the number or routers
+ * @param symm if latency is symmetric between all pairs of routers
+ */
+public static void reset(int size, boolean symm)
+{
+       E2ENetwork.symm = symm;
+       E2ENetwork.size = size;
+       array = new int[size][];
+       for (int i=0; i < size; i++) {
+               if (symm)
+                       array[i] = new int[i];
+               else
+                       array[i] = new int[size];
+       }
+}
+       
+//---------------------------------------------------------------------
+
+/**
+ * Returns the latency associated to the specified (sender, receiver)
+ * pair. Routers are indexed from 0.
+ * 
+ * @param sender the index of the sender
+ * @param receiver the index of the receiver
+ * @return the latency associated to the specified (sender, receiver)
+ * pair.
+ */
+public static int getLatency(int sender, int receiver) 
+{
+       if (sender == receiver)
+               return 0;
+       // XXX There should be the possibility to fix the delay.
+       if (symm) {
+               // Symmetric network
+               if (sender < receiver) {
+                       int tmp = sender;
+                       sender = receiver;
+                       receiver = tmp;
+               }
+       } 
+       return array[sender][receiver];
+}
+
+//---------------------------------------------------------------------
+
+/**
+ * Sets the latency associated to the specified (sender, receiver)
+ * pair. Routers are indexed from 0.
+ * 
+ * @param sender the index of the sender
+ * @param receiver the index of the receiver
+ * @param latency the latency to be set
+ */
+public static void setLatency(int sender, int receiver, int latency) 
+{
+       if (symm) {
+               // Symmetric network
+               if (sender < receiver) {
+                       int tmp = sender;
+                       sender = receiver;
+                       receiver = tmp;
+               }
+       } 
+       array[sender][receiver] = latency;
+}
+
+//---------------------------------------------------------------------
+
+/**
+ * Returns the current size of the underlying network (i.e., the number of
+ * routers).
+ */
+public static int getSize()
+{
+       return size;
+}
+
+}
diff --git a/contrib/psg/src/peersim/transport/E2ETransport.java b/contrib/psg/src/peersim/transport/E2ETransport.java
new file mode 100644 (file)
index 0000000..e2eab78
--- /dev/null
@@ -0,0 +1,156 @@
+/*
+ * 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.transport;
+
+import peersim.config.*;
+import peersim.core.*;
+import peersim.edsim.*;
+
+
+/**
+ * This transport protocol is based on the {@link E2ENetwork} class.
+ * Each instance
+ * of this transport class is assigned to one of the routers contained in
+ * the (fully static singleton) {@link E2ENetwork},
+ * and subsequently the {@link E2ENetwork} class is used to obtain the
+ * latency for messages sending based on the router assignment.
+ *
+ * @author Alberto Montresor
+ * @version $Revision: 1.11 $
+ */
+public class E2ETransport implements Transport, RouterInfo
+{
+
+//---------------------------------------------------------------------
+//Parameters
+//---------------------------------------------------------------------
+
+/**
+ * The delay that corresponds to the time spent on the source (and destination)
+ * nodes. In other words, full latency is calculated by fetching the latency
+ * that belongs to communicating between two routers, incremented by
+ * twice this delay. Defaults to 0.
+ * @config
+ */
+private static final String PAR_LOCAL = "local";
+       
+//---------------------------------------------------------------------
+//Static fields
+//---------------------------------------------------------------------
+
+/** Identifier of this transport protocol */
+private static int tid;
+       
+/** Local component of latency */
+private static long local;
+
+//---------------------------------------------------------------------
+//Fields
+//---------------------------------------------------------------------
+
+/** Identifier of the internal node */
+private int router = -1;
+       
+//---------------------------------------------------------------------
+//Initialization
+//---------------------------------------------------------------------
+
+/**
+ * Reads configuration parameters.
+ */
+public E2ETransport(String prefix)
+{
+       tid = CommonState.getPid();
+       local = Configuration.getLong(prefix + "." + PAR_LOCAL, 0);
+}
+
+//---------------------------------------------------------------------
+
+/**
+ * Clones the object.
+ */
+public Object clone()
+{
+       E2ETransport e2e=null;
+       try { e2e=(E2ETransport)super.clone(); }
+       catch( CloneNotSupportedException e ) {} // never happens
+       return e2e;
+}
+
+//---------------------------------------------------------------------
+//Methods inherited by Transport
+//---------------------------------------------------------------------
+
+/**
+* Delivers the message reliably, with the latency calculated by
+* {@link #getLatency}.
+*/
+public void send(Node src, Node dest, Object msg, int pid)
+{
+       /* Assuming that the sender corresponds to the source node */
+       E2ETransport sender = (E2ETransport) src.getProtocol(tid);
+       E2ETransport receiver = (E2ETransport) dest.getProtocol(tid);
+       long latency =
+          E2ENetwork.getLatency(sender.router, receiver.router) + local*2;
+       EDSimulator.add(latency, msg, dest, pid);
+}
+
+//---------------------------------------------------------------------
+
+/**
+* Calculates latency using the static singleton {@link E2ENetwork}.
+* It looks up which routers the given nodes are assigned to, then
+* looks up the corresponding latency. Finally it increments this value
+* by adding twice the local delay configured by {@value #PAR_LOCAL}.
+*/
+public long getLatency(Node src, Node dest)
+{
+       /* Assuming that the sender corresponds to the source node */
+       E2ETransport sender = (E2ETransport) src.getProtocol(tid);
+       E2ETransport receiver = (E2ETransport) dest.getProtocol(tid);
+       return E2ENetwork.getLatency(sender.router, receiver.router) + local*2;
+}
+
+
+//---------------------------------------------------------------------
+//Methods inherited by RouterInfo
+//---------------------------------------------------------------------
+
+/**
+ * Associates the node hosting this transport protocol instance with
+ * a router in the router network.
+ * 
+ * @param router the numeric index of the router 
+ */
+public void setRouter(int router)
+{
+       this.router = router;
+}
+
+//---------------------------------------------------------------------
+
+/**
+ * @return the router associated to this transport protocol.
+ */
+public int getRouter()
+{
+       return router;
+}
+
+}
diff --git a/contrib/psg/src/peersim/transport/KingParser.java b/contrib/psg/src/peersim/transport/KingParser.java
new file mode 100644 (file)
index 0000000..1471796
--- /dev/null
@@ -0,0 +1,166 @@
+/*
+ * 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.transport;
+
+import java.io.*;
+import java.util.*;
+import peersim.config.*;
+import peersim.core.Control;
+
+/**
+ * Initializes static singleton {@link E2ENetwork} by reading a king data set.
+ * 
+ * @author Alberto Montresor
+ * @version $Revision: 1.9 $
+ */
+public class KingParser implements Control
+{
+
+// ---------------------------------------------------------------------
+// Parameters
+// ---------------------------------------------------------------------
+
+/**
+ * The file containing the King measurements.
+ * @config
+ */
+private static final String PAR_FILE = "file";
+
+/**
+ * The ratio between the time units used in the configuration file and the
+ * time units used in the Peersim simulator.
+ * @config
+ */
+private static final String PAR_RATIO = "ratio";
+
+// ---------------------------------------------------------------------
+// Fields
+// ---------------------------------------------------------------------
+
+/** Name of the file containing the King measurements. */
+private String filename;
+
+/**
+ * Ratio between the time units used in the configuration file and the time
+ * units used in the Peersim simulator.
+ */
+private double ratio;
+
+/** Prefix for reading parameters */
+private String prefix;
+
+// ---------------------------------------------------------------------
+// Initialization
+// ---------------------------------------------------------------------
+
+/**
+ * Read the configuration parameters.
+ */
+public KingParser(String prefix)
+{
+       this.prefix = prefix;
+       ratio = Configuration.getDouble(prefix + "." + PAR_RATIO, 1);
+       filename = Configuration.getString(prefix + "." + PAR_FILE, null);
+}
+
+// ---------------------------------------------------------------------
+// Methods
+// ---------------------------------------------------------------------
+
+/**
+ * Initializes static singleton {@link E2ENetwork} by reading a king data set.
+* @return  always false
+*/
+public boolean execute()
+{
+       BufferedReader in = null;
+       if (filename != null) {
+               try {
+                       in = new BufferedReader(new FileReader(filename));
+               } catch (FileNotFoundException e) {
+                       throw new IllegalParameterException(prefix + "." + PAR_FILE, filename
+                                       + " does not exist");
+               }
+       } else {
+               in = new BufferedReader( new InputStreamReader(
+                                               ClassLoader.getSystemResourceAsStream("t-king.map")
+                                       )       );
+       }
+               
+       // XXX If the file format is not correct, we will get quite obscure
+       // exceptions. To be improved.
+
+       String line = null;
+       // Skip initial lines
+       int size = 0;
+       int lc = 1;
+       try {
+               while ((line = in.readLine()) != null && !line.startsWith("node")) lc++;
+               while (line != null && line.startsWith("node")) {
+                       size++;
+                       lc++;
+                       line = in.readLine();
+               }
+       } catch (IOException e) {
+               System.err.println("KingParser: " + filename + ", line " + lc + ":");
+               e.printStackTrace();
+               try { in.close(); } catch (IOException e1) { };
+               System.exit(1);
+       }
+       E2ENetwork.reset(size, true);
+       if (line == null) {
+               System.err.println("KingParser: " + filename + ", line " + lc + ":");
+               System.err.println("No latency matrix contained in the specified file");
+               try { in.close(); } catch (IOException e1) { };
+               System.exit(1);
+       }
+       
+       System.err.println("KingParser: read " + size + " entries");
+       
+       try {
+               do {
+                       StringTokenizer tok = new StringTokenizer(line, ", ");
+                       if (tok.countTokens() != 3) {
+                               System.err.println("KingParser: " + filename + ", line " + lc + ":");
+                               System.err.println("Specified line does not contain a <node1, node2, latency> triple");
+                               try { in.close(); } catch (IOException e1) { };
+                               System.exit(1);
+                       }
+                       int n1 = Integer.parseInt(tok.nextToken()) - 1;
+                       int n2 = Integer.parseInt(tok.nextToken()) - 1;
+                       int latency = (int) (Double.parseDouble(tok.nextToken()) * ratio);
+                       E2ENetwork.setLatency(n1, n2, latency);
+                       lc++;
+                       line = in.readLine();
+               } while (line != null);
+               
+               in.close();
+       
+       } catch (IOException e) {
+               System.err.println("KingParser: " + filename + ", line " + lc + ":");
+               e.printStackTrace();
+               try { in.close(); } catch (IOException e1) { };
+               System.exit(1);
+       }
+
+
+       return false;
+}
+
+}
diff --git a/contrib/psg/src/peersim/transport/RouterInfo.java b/contrib/psg/src/peersim/transport/RouterInfo.java
new file mode 100644 (file)
index 0000000..be3c168
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * 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.transport;
+
+/**
+ * Generic interface to be implemented by protocols that need to be assigned to
+ * routers. The idea is that each node is assigned to a router, by
+ * invoking {@link #setRouter(int)} method. Routers are identified by
+ * integer indexes (starting from 0), based on the assumption that the
+ * router network
+ * is static. The router information is then used by different 
+ * implementations to compute latency, congestion, etc.
+ *
+ * @author Alberto Montresor
+ * @version $Revision: 1.4 $
+ */
+public interface RouterInfo
+{
+
+/**
+ * Associates the node hosting this transport protocol instance with
+ * a router in the router network.
+ * 
+ * @param router the numeric index of the router 
+ */
+public void setRouter(int router);
+
+/**
+ * @return the router associated to this transport protocol.
+ */
+public int getRouter();
+
+}
diff --git a/contrib/psg/src/peersim/transport/Transport.java b/contrib/psg/src/peersim/transport/Transport.java
new file mode 100644 (file)
index 0000000..4606283
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * 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.transport;
+
+import peersim.core.*;
+
+
+/**
+ * This interface represents a generic transport protocol, used to
+ * send messages through the underlying network. Generally, transport
+ * protocols use {@link peersim.edsim.EDSimulator} to schedule the delivery of
+ * messages with some appropriate delay. They can also model message omission
+ * failure as well.
+ * 
+ * @author Alberto Montresor
+ * @version $Revision: 1.7 $
+ */
+public interface Transport extends Protocol
+{
+       
+/**
+ * Sends message <code>msg</code>      from node <code>src</code> to protocol
+ * <code>pid</code> of node <code>dst</code>.
+ * 
+ * @param src sender node
+ * @param dest destination node
+ * @param msg message to be sent
+ * @param pid protocol identifier
+ */
+public void send(Node src, Node dest, Object msg, int pid);
+
+
+/**
+ * Return a latency estimate from node <code>src</code> to protocol
+ * <code>pid</code> of node <code>dst</code>. 
+ * 
+ * @param src sender node
+ * @param dest destination node
+ */
+public long getLatency(Node src, Node dest);
+
+
+}
diff --git a/contrib/psg/src/peersim/transport/TriangularMatrixParser.java b/contrib/psg/src/peersim/transport/TriangularMatrixParser.java
new file mode 100644 (file)
index 0000000..d3f0768
--- /dev/null
@@ -0,0 +1,140 @@
+/*
+ * 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.transport;
+
+import java.io.*;
+
+import peersim.config.*;
+import peersim.core.*;
+
+/**
+ * Initializes static singleton {@link E2ENetwork} by reading a trace 
+ * file containing the latency distance measured between a set of 
+ * "virtual" routers. Latency is assumed to be symmetric, so the 
+ * latency between x and y is equal to the latency to y and x.
+ * 
+ * The format of the file is as follows: all values are stored as
+ * integers. The first value is the number of nodes considered.
+ * The rest of the values correspond to a "strictly upper triangular 
+ * matrix" (see this 
+ * <a href="http://en.wikipedia.org/w/index.php?title=Triangular_matrix&oldid=82411128">
+ * link</a>), ordered first by row than by column.
+ * 
+ * @author Alberto Montresor
+ * @version $Revision: 1.4 $
+ */
+public class TriangularMatrixParser implements Control
+{
+
+// ---------------------------------------------------------------------
+// Parameters
+// ---------------------------------------------------------------------
+
+/**
+ * This configuration parameter identifies the filename of the file
+ * containing the measurements. First, the file is used as a pathname 
+ * in the local file system. If no file can be identified in this way, 
+ * the file is searched in the local classpath. If the file cannot be 
+ * identified again, an error message is reported.
+ * @config
+ */
+private static final String PAR_FILE = "file";
+
+/**
+ * The ratio between the time units used in the configuration file and the
+ * time units used in the Peersim simulator.
+ * @config
+ */
+private static final String PAR_RATIO = "ratio";
+
+// ---------------------------------------------------------------------
+// Fields
+// ---------------------------------------------------------------------
+
+/** Name of the file containing the measurements. */
+private String filename;
+
+/** Ratio read from PAR_RATIO */
+private double ratio;
+
+// ---------------------------------------------------------------------
+// Initialization
+// ---------------------------------------------------------------------
+
+/**
+ * Read the configuration parameters.
+ */
+public TriangularMatrixParser(String prefix)
+{
+       filename = Configuration.getString(prefix + "." + PAR_FILE);
+       ratio = Configuration.getDouble(prefix + "." + PAR_RATIO);
+}
+
+// ---------------------------------------------------------------------
+// Methods
+// ---------------------------------------------------------------------
+
+/**
+ * Initializes static singleton {@link E2ENetwork} by reading a king data set.
+* @return  always false
+*/
+public boolean execute()
+{
+       try {
+               ObjectInputStream in = null;
+               try {
+                       in = new ObjectInputStream(
+                                       new BufferedInputStream(
+                                                       new FileInputStream(filename)));
+                       System.err.println("TriangularMatrixParser: Reading " + filename + " from local file system");
+               } catch (FileNotFoundException e) {
+                       in = new ObjectInputStream(
+                                       new BufferedInputStream(
+                                                       ClassLoader.getSystemResourceAsStream(filename)));
+                       System.err.println("TriangularMatrixParser: Reading " + filename + " through the class loader");
+               }
+       
+               // Read the number of nodes in the file (first four bytes).
+         int size = in.readInt();
+         
+               // Reset the E2E network
+               E2ENetwork.reset(size, true);
+               System.err.println("TriangularMatrixParser: reading " + size + " rows");
+       
+               // If the file format is not correct, data will be read 
+               // incorrectly. Probably a good way to spot this is the 
+               // presence of negative delays, or an end of file.
+       
+               // Reading data
+               int count = 0;
+               for (int r=0; r < size; r++) {
+                       for (int c = r+1; c < size; c++) {
+                               int x = (int) (ratio*in.readInt());
+                               count++;
+                               E2ENetwork.setLatency(r,c,x);
+                       }
+               }
+               System.err.println("TriangularMatrixParser: Read " + count + " entries");
+       } catch (IOException e) {
+               throw new RuntimeException(e.getMessage());
+       }
+       return false;
+}
+
+}
diff --git a/contrib/psg/src/peersim/transport/UniformRandomTransport.java b/contrib/psg/src/peersim/transport/UniformRandomTransport.java
new file mode 100644 (file)
index 0000000..1abc6d8
--- /dev/null
@@ -0,0 +1,123 @@
+/*
+ * 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.transport;
+
+import peersim.config.*;
+import peersim.core.*;
+import peersim.edsim.*;
+
+
+/**
+ * Implement a transport layer that reliably delivers messages with a random
+ * delay, that is drawn from the configured interval according to the uniform
+ * distribution.
+ *
+ * @author Alberto Montresor
+ * @version $Revision: 1.14 $
+ */
+public final class UniformRandomTransport implements Transport
+{
+
+//---------------------------------------------------------------------
+//Parameters
+//---------------------------------------------------------------------
+
+/** 
+ * String name of the parameter used to configure the minimum latency.
+ * @config
+ */    
+private static final String PAR_MINDELAY = "mindelay"; 
+       
+/** 
+ * String name of the parameter used to configure the maximum latency.
+ * Defaults to {@value #PAR_MINDELAY}, which results in a constant delay.
+ * @config 
+ */    
+private static final String PAR_MAXDELAY = "maxdelay"; 
+       
+//---------------------------------------------------------------------
+//Fields
+//---------------------------------------------------------------------
+
+/** Minimum delay for message sending */
+private final long min;
+       
+/** Difference between the max and min delay plus one. That is, max delay is
+* min+range-1.
+*/
+private final long range;
+
+       
+//---------------------------------------------------------------------
+//Initialization
+//---------------------------------------------------------------------
+
+/**
+ * Reads configuration parameter.
+ */
+public UniformRandomTransport(String prefix)
+{
+       min = Configuration.getLong(prefix + "." + PAR_MINDELAY);
+       long max = Configuration.getLong(prefix + "." + PAR_MAXDELAY,min);
+       if (max < min) 
+          throw new IllegalParameterException(prefix+"."+PAR_MAXDELAY, 
+          "The maximum latency cannot be smaller than the minimum latency");
+       range = max-min+1;
+}
+
+//---------------------------------------------------------------------
+
+/**
+* Returns <code>this</code>. This way only one instance exists in the system
+* that is linked from all the nodes. This is because this protocol has no
+* node specific state.
+*/
+public Object clone()
+{
+       return this;
+}
+
+//---------------------------------------------------------------------
+//Methods
+//---------------------------------------------------------------------
+
+/**
+ * Delivers the message with a random
+ * delay, that is drawn from the configured interval according to the uniform
+ * distribution.
+*/
+public void send(Node src, Node dest, Object msg, int pid)
+{
+       // avoid calling nextLong if possible
+       long delay = (range==1?min:min + CommonState.r.nextLong(range));
+       EDSimulator.add(delay, msg, dest, pid);
+}
+
+/**
+ * Returns a random
+ * delay, that is drawn from the configured interval according to the uniform
+ * distribution.
+*/
+public long getLatency(Node src, Node dest)
+{
+       return (range==1?min:min + CommonState.r.nextLong(range));
+}
+
+
+}
diff --git a/contrib/psg/src/peersim/transport/UniformRouterAssignment.java b/contrib/psg/src/peersim/transport/UniformRouterAssignment.java
new file mode 100644 (file)
index 0000000..064ba7d
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * 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.transport;
+
+import peersim.config.*;
+import peersim.core.*;
+
+
+/**
+ * Initializes {@link RouterInfo} protocols by assigning routers to them.
+ * The number of routers is defined by static singleton {@link E2ENetwork}.
+ *
+ * @author Alberto Montresor
+ * @version $Revision: 1.6 $
+ */
+public class UniformRouterAssignment implements Control
+{
+
+//---------------------------------------------------------------------
+//Parameters
+//---------------------------------------------------------------------
+
+/** 
+ * Parameter name used to configure the {@link RouterInfo} protocol
+ * that should be initialized.
+ * @config 
+ */
+private static final String PAR_PROT = "protocol"; 
+       
+//---------------------------------------------------------------------
+//Methods
+//---------------------------------------------------------------------
+
+/** Protocol identifier */
+private int pid;       
+       
+
+//---------------------------------------------------------------------
+//Initialization
+//---------------------------------------------------------------------
+
+/**
+ * Reads configuration parameters.
+ */
+public UniformRouterAssignment(String prefix)
+{
+       pid = Configuration.getPid(prefix+"."+PAR_PROT);
+}
+
+//---------------------------------------------------------------------
+//Methods
+//---------------------------------------------------------------------
+
+/**
+ * Initializes given {@link RouterInfo} protocol layer by assigning
+ * routers randomly.
+ * The number of routers is defined by static singleton {@link E2ENetwork}.
+* @return always false
+*/
+public boolean execute()
+{
+       int nsize = Network.size();
+       int nrouters = E2ENetwork.getSize();
+       for (int i=0; i < nsize; i++) {
+               Node node = Network.get(i);
+               RouterInfo t = (RouterInfo) node.getProtocol(pid);
+               int r = CommonState.r.nextInt(nrouters);
+               t.setRouter(r);
+       }
+
+       return false;
+}
+
+}
+
diff --git a/contrib/psg/src/peersim/transport/UnreliableTransport.java b/contrib/psg/src/peersim/transport/UnreliableTransport.java
new file mode 100644 (file)
index 0000000..9460880
--- /dev/null
@@ -0,0 +1,129 @@
+/*
+ * 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.transport;
+
+import peersim.config.*;
+import peersim.core.*;
+
+
+/**
+ * This transport protocol can be combined with other transports
+ * to simulate message losses. Its behavior is the following: each message
+ * can be dropped based on the configured probability, or it will be sent
+ * using the underlying transport protocol. 
+ * <p>
+ * The memory requirements are minimal, as a single instance is created and 
+ * inserted in the protocol array of all nodes (because instances have no state
+ * that depends on the hosting node). 
+ *
+ * @author Alberto Montresor
+ * @version $Revision: 1.13 $
+ */
+public final class UnreliableTransport implements Transport
+{
+
+//---------------------------------------------------------------------
+//Parameters
+//---------------------------------------------------------------------
+
+/**
+ * The name of the underlying transport protocol. This transport is
+ * extended with dropping messages.
+ * @config
+ */
+private static final String PAR_TRANSPORT = "transport";
+
+/** 
+ * String name of the parameter used to configure the probability that a 
+ * message sent through this transport is lost.
+ * @config
+ */
+private static final String PAR_DROP = "drop";
+
+
+//---------------------------------------------------------------------
+//Fields
+//---------------------------------------------------------------------
+
+/** Protocol identifier for the support transport protocol */
+private final int transport;
+
+/** Probability of dropping messages */
+private final float loss;
+
+//---------------------------------------------------------------------
+//Initialization
+//---------------------------------------------------------------------
+
+/**
+ * Reads configuration parameter.
+ */
+public UnreliableTransport(String prefix)
+{
+       transport = Configuration.getPid(prefix+"."+PAR_TRANSPORT);
+       loss = (float) Configuration.getDouble(prefix+"."+PAR_DROP);
+}
+
+//---------------------------------------------------------------------
+
+/**
+* Returns <code>this</code>. This way only one instance exists in the system
+* that is linked from all the nodes. This is because this protocol has no
+* state that depends on the hosting node.
+ */
+public Object clone()
+{
+       return this;
+}
+
+//---------------------------------------------------------------------
+//Methods
+//---------------------------------------------------------------------
+
+/** Sends the message according to the underlying transport protocol.
+* With the configured probability, the message is not sent (i.e. the method does
+* nothing).
+*/
+public void send(Node src, Node dest, Object msg, int pid)
+{
+       try
+       {
+               if (CommonState.r.nextFloat() >= loss)
+               {
+                       // Message is not lost
+                       Transport t = (Transport) src.getProtocol(transport);
+                       t.send(src, dest, msg, pid);
+               }
+       }
+       catch(ClassCastException e)
+       {
+               throw new IllegalArgumentException("Protocol " +
+                               Configuration.lookupPid(transport) + 
+                               " does not implement Transport");
+       }
+}
+
+/** Returns the latency of the underlying protocol.*/
+public long getLatency(Node src, Node dest)
+{
+       Transport t = (Transport) src.getProtocol(transport);
+       return t.getLatency(src, dest);
+}
+
+}
diff --git a/contrib/psg/src/peersim/util/ExtendedRandom.java b/contrib/psg/src/peersim/util/ExtendedRandom.java
new file mode 100644 (file)
index 0000000..14e713e
--- /dev/null
@@ -0,0 +1,123 @@
+/*
+ * 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.util;
+
+import java.util.Random;
+import java.lang.Math;
+
+/**
+ * Extends the functionality of <code>java.util.Random</code>.
+ */
+public class ExtendedRandom extends Random {
+
+private long lastSeed;
+
+// -------------------------------------------------------------------------
+
+/** Calls super constructor. Also stores the seed to be returned by
+{@link #getLastSeed}. */
+public ExtendedRandom(long seed) {
+       
+       super(seed);
+       lastSeed = seed;
+}
+
+// -------------------------------------------------------------------------
+
+/**
+ * Extracts the next integer, according to a Poisson distribution.
+ * 
+ * @param mean The mean of the Poisson distribution.
+ * @return An integer Poisson extraction.
+ */
+public int nextPoisson(double mean) {
+       
+       double emean = Math.exp(-1 * mean);
+       double product = 1;
+       int count = 0;
+       int result = 0;
+       while (product >= emean) {
+               product *= nextDouble();
+               result = count;
+               count++; // keep result one behind
+       }
+       return result;
+}
+
+// -------------------------------------------------------------------------
+
+/**
+* Implements nextLong(long) the same way nexInt(int) is implemented in
+* java.util.Random.
+* @param n the bound on the random number to be returned. Must be positive.
+* @return a pseudorandom, uniformly distributed long value between 0
+* (inclusive) and n (exclusive).
+*/
+public long nextLong(long n) {
+
+       if (n<=0)
+               throw new IllegalArgumentException("n must be positive");
+       
+       if ((n & -n) == n)  // i.e., n is a power of 2
+       {       
+               return nextLong()&(n-1);
+       }
+       
+       long bits, val;
+       do
+       {
+               bits = (nextLong()>>>1);
+               val = bits % n;
+       }
+       while(bits - val + (n-1) < 0);
+       
+       return val;
+}
+
+// -------------------------------------------------------------------------
+
+/** Sets random seed. Calls super method but also stores the seed to be
+returned by {@link #getLastSeed}. */
+public void setSeed( long seed ) {
+       
+       super.setSeed(seed);
+       lastSeed = seed;
+}
+
+// -------------------------------------------------------------------------
+
+/**
+* Returns the last random seed that was set explicitly. Either at
+* construction time or through {@link #setSeed}.
+*/
+public long getLastSeed() { return lastSeed; }
+
+// -------------------------------------------------------------------------
+
+/*
+public static void main(String[] args) {
+
+       ExtendedRandom er = new ExtendedRandom(12345678);
+       for(int i=0; i<100; ++i)
+               System.out.println(er.nextLong(Long.parseLong(args[0])));
+       
+}
+*/
+}
+
diff --git a/contrib/psg/src/peersim/util/FileNameGenerator.java b/contrib/psg/src/peersim/util/FileNameGenerator.java
new file mode 100644 (file)
index 0000000..c07d925
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ * 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.util;
+
+import java.io.*;
+
+
+/**
+* Generates a series of filenames for classes that have to save e.g.
+* snapshots regularly.
+*/
+public class FileNameGenerator {
+
+
+/**
+* The number of filenames already returned.
+*/
+private long counter = 0;
+
+/** The prefix of the filename */
+public final String prefix;
+
+/** The extension of the filename */
+public final String ext;
+
+
+// ==================== initialization ==============================
+// ==================================================================
+
+
+/**
+* @param prefix all returned names will be prefixed by this
+* @param ext will be appended to all returned names
+*/
+public FileNameGenerator(String prefix, String ext) {
+       
+       this.prefix=prefix;
+       this.ext=ext;
+}
+
+
+// ===================== methods ====================================
+// ==================================================================
+
+
+/**
+* Generates a name based on a counter.
+* The format of the name returned is {@link #prefix} followed by
+* an 8 digit zero padded number, followed by {@link #ext}.
+* The first number used is zero.
+* @return the next filename after increasing the counter
+*/
+public String nextCounterName() {
+       
+       ByteArrayOutputStream baos = new ByteArrayOutputStream();
+       (new PrintStream(baos)).printf("%08d",counter);
+       counter++;
+       return prefix+baos.toString()+ext;
+}
+
+// ------------------------------------------------------------------
+
+/*
+public static void main(String args[]) {
+       
+       FileNameGenerator fng = new FileNameGenerator(args[0],args[1]);
+       for(int i=0; i<100; ++i) System.err.println(fng.nextCounterName()); 
+}
+*/
+}
+
diff --git a/contrib/psg/src/peersim/util/IncrementalFreq.java b/contrib/psg/src/peersim/util/IncrementalFreq.java
new file mode 100644 (file)
index 0000000..3352daf
--- /dev/null
@@ -0,0 +1,312 @@
+/*
+ * 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.util;
+
+import java.io.PrintStream;
+
+//XXX This implementation is very restricted, to be made more flexible
+// using hashtables.
+/**
+* A class that can collect frequency information on integer input.
+* right now it can handle only unsigned input. It simply ignores negative
+* numbers.
+*/
+public class IncrementalFreq implements Cloneable {
+
+
+// ===================== fields ========================================
+// =====================================================================
+
+/** The number of items inserted. */
+private int n;
+
+/** freq[i] holds the frequency of i. primitive implementation, to be changed */
+private int[] freq = null; 
+
+/**
+* The capacity, if larger than 0. Added values larger than or equal to
+* this one will be ignored.
+*/
+private final int N;
+
+
+// ====================== initialization ==============================
+// ====================================================================
+
+
+/**
+* @param maxvalue Values in the input set larger than this one will be ignored.
+* However, if it is negative, no values are ignored.
+*/
+public IncrementalFreq(int maxvalue) {
+       
+       N = maxvalue+1;
+       reset();
+}
+
+// --------------------------------------------------------------------
+
+/** Calls <code>this(-1)</code>, that is, no values will be ignored.
+* @see #IncrementalFreq(int) */
+public IncrementalFreq() {
+       
+       this(-1);
+}
+
+// --------------------------------------------------------------------
+
+/** Reset the state of the object. After calling this, all public methods
+* behave the same as they did after constructing the object.
+*/
+public void reset() {
+
+       if( freq==null || N==0 ) freq = new int[0];
+       else for(int i=0; i<freq.length; ++i) freq[i]=0;
+       n = 0;
+}
+
+
+// ======================== methods ===================================
+// ====================================================================
+
+/**
+ * Adds item <code>i</code> to the input set.
+ * It calls <code>add(i,1)</code>.
+ * @see #add(int,int)
+ */
+public final void add( int i ) { add(i,1); }
+
+
+// --------------------------------------------------------------------
+
+/**
+ * Adds item <code>i</code> to the input set <code>k</code> times.
+ * That is, it increments counter <code>i</code> by <code>k</code>.
+ * If, however, <code>i</code> is negative, or larger than the maximum defined
+ * at construction time (if a maximum was set at all) the operation is ignored.
+ */
+public void add( int i, int k ) {
+  
+  if( N>0 && i>=N ) return;
+  if( i<0 || k<=0 ) return;
+
+  // Increase number of items by k.
+  n+=k;
+
+  // If index i is out of bounds for the current array of counters,
+  // increase the size of the array to i+1.
+  if( i>=freq.length )
+  {
+    int tmp[] = new int[i+1];
+    System.arraycopy(freq, 0, tmp, 0, freq.length);
+    freq=tmp;
+  }
+
+  // Finally, increase counter i by k.
+  freq[i]+=k;
+}
+
+// --------------------------------------------------------------------
+
+/** Returns number of processed data items.
+* This is the number of items over which the class holds statistics.
+*/
+public int getN() { return n; }
+
+// --------------------------------------------------------------------
+
+/** Returns the number of occurrences of the given integer. */
+public int getFreq(int i) {
+       
+       if( i>=0 && i<freq.length ) return freq[i];
+       else return 0;
+}
+
+// --------------------------------------------------------------------
+       
+
+/**
+ * Performs an element-by-element vector subtraction of the
+ * frequency vectors. If <code>strict</code> is true, it
+ * throws an IllegalArgumentException if <code>this</code> is
+ * not strictly larger than <code>other</code> (element by element)
+ * (Note that both frequency vectors are positive.)
+ * Otherwise just sets those elements in <code>this</code> to zero
+ * that are smaller than those of <code>other</code>.
+ * @param other The instance of IncrementalFreq to subtract
+ * @param strict See above explanation
+ */
+public void remove(IncrementalFreq other, boolean strict) {
+
+       // check if other has non-zero elements in non-overlapping part
+       if(strict && other.freq.length>freq.length)
+       {
+               for(int i=other.freq.length-1; i>=freq.length; --i)
+               {
+                       if (other.freq[i]!=0)
+                               throw new IllegalArgumentException();
+               }
+       }
+       
+       final int minLength = Math.min(other.freq.length, freq.length);
+       for (int i=minLength-1; i>=0; i--)
+       {
+               if (strict && freq[i] < other.freq[i])
+                       throw new IllegalArgumentException();
+               final int remove = Math.min(other.freq[i], freq[i]);
+               n -= remove;
+               freq[i] -= remove;
+       }
+}
+
+// ---------------------------------------------------------------------
+
+/**
+* Prints current frequency information. Prints a separate line for
+* all values from 0 to the capacity of the internal representation using the
+* format
+* <pre>
+* value occurrences
+* </pre>
+* That is, numbers with zero occurrences will also be printed. 
+*/
+public void printAll( PrintStream out ) {
+       
+       for(int i=0; i<freq.length; ++i)
+       {
+               out.println(i+" "+freq[i]);
+       }
+}
+
+// ---------------------------------------------------------------------
+
+/**
+* Prints current frequency information. Prints a separate line for
+* all values that have a number of occurrences different from zero using the 
+* format
+* <pre>
+* value occurrences
+* </pre>
+*/
+public void print( PrintStream out ) {
+
+       for(int i=0; i<freq.length; ++i)
+       {
+               if(freq[i]!=0) out.println(i+" "+freq[i]);
+       }
+}
+
+// ---------------------------------------------------------------------
+
+public String toString() {
+       
+       StringBuilder result=new StringBuilder("");
+       for(int i=0; i<freq.length; ++i)
+       {
+               if (freq[i] != 0)
+                       result.append(" (").append(i).append(","
+                       ).append(freq[i]).append(")");
+       }
+       return result.toString();
+}
+
+// ---------------------------------------------------------------------
+
+/** An alternative method to convert the object to String */
+public String toArithmeticExpression() {
+
+       StringBuilder result=new StringBuilder("");
+       for (int i=freq.length-1; i>=0; i--)
+       {
+               if (freq[i] != 0)
+                       result.append(freq[i]).append(
+                       "*").append(i).append("+");
+       }
+       
+       if (result.length()==0)
+               return "(empty)";
+       else
+               return result.substring(0, result.length()-1);
+}
+
+// ---------------------------------------------------------------------
+
+public Object clone() throws CloneNotSupportedException {
+
+       IncrementalFreq result = (IncrementalFreq)super.clone();
+       if( freq != null ) result.freq = freq.clone();
+       return result;
+}
+
+// ---------------------------------------------------------------------
+
+/**
+* Tests equality between two IncrementalFreq instances.
+* Two objects are equal if both hold the same set of numbers that have
+* occurred non-zero times and the number of occurrences is also equal for
+* these numbers.
+*/
+public boolean equals(Object obj) {
+
+       if( !( obj instanceof IncrementalFreq) ) return false;
+       IncrementalFreq other = (IncrementalFreq)obj;
+       final int minlength = Math.min(other.freq.length, freq.length);
+       
+       for (int i=minlength-1; i>=0; i--)
+               if (freq[i] != other.freq[i])
+                       return false;
+
+       if( freq.length > minlength ) other=this;
+       for (int i=minlength; i<other.freq.length; i++)
+               if( other.freq[i] != 0 )
+                       return false;
+
+       return true;
+}
+
+// ---------------------------------------------------------------------
+
+/**
+* Hashcode (consistent with {@link #equals}). Probably you will never want to
+* use this, but since we have {@link #equals}, we must implement it.
+*/
+public int hashCode() {
+
+       int sum = 0;
+       for(int i=0; i<freq.length; ++i) sum += freq[i]*i;
+       return sum;
+}
+
+// ---------------------------------------------------------------------
+
+/*
+public static void main(String[] pars) {
+       
+       IncrementalFreq ifq = new IncrementalFreq(Integer.parseInt(pars[0]));
+       for(int i=1; i<pars.length; ++i)
+       {
+               ifq.add(Integer.parseInt(pars[i]));
+       }
+       ifq.print(System.out);
+       System.out.println(ifq);
+}
+*/
+}
+
+
diff --git a/contrib/psg/src/peersim/util/IncrementalStats.java b/contrib/psg/src/peersim/util/IncrementalStats.java
new file mode 100644 (file)
index 0000000..eb48d69
--- /dev/null
@@ -0,0 +1,187 @@
+/*
+ * 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.util;
+
+/**
+* A class that can keep track of some statistics like variance, average, min,
+* max incrementally. That is, when adding a new data item, it updates the
+* statistics.
+*/
+public class IncrementalStats {
+
+
+// ===================== fields ========================================
+// =====================================================================
+
+
+private double min;
+
+private double max;
+
+private double sum;
+
+private double sqrsum;
+
+private int n;
+
+private int countmin;
+
+private int countmax;
+
+// ====================== initialization ==============================
+// ====================================================================
+
+
+/** Calls {@link #reset}. */
+public IncrementalStats() { reset(); }
+
+// --------------------------------------------------------------------
+
+/** Resets the statistics to reflect the zero elements set.
+* Min and max are set to positive and negative infinity, respectively.
+*/
+public void reset() {
+       
+       countmin=0;
+       countmax=0;
+       min = Double.POSITIVE_INFINITY;
+       max = Double.NEGATIVE_INFINITY;
+       sum = 0.0;
+       sqrsum = 0.0;
+       n = 0;
+}
+
+
+// ======================== methods ===================================
+// ====================================================================
+
+
+/** Updates the statistics according to this element. It calls
+* <code>add(item,1)</code>.
+* @see #add(double,int) */
+public final void add( double item ) { add(item,1); }
+
+// --------------------------------------------------------------------
+
+/** Updates the statistics assuming element <code>item</code> is added
+* <code>k</code> times.*/
+public void add( double item, int k ) {
+       
+       if( item < min )
+       {
+               min = item;
+               countmin = 0;
+       } 
+       if( item == min ) countmin+=k;
+       if( item > max )
+       {
+               max = item;
+               countmax = 0;
+       }
+       if(item == max) countmax+=k;  
+       n+=k;
+       if( k == 1 )
+       {
+               sum += item;
+               sqrsum += item*item;
+       }
+       else
+       {
+               sum += item*k;
+               sqrsum += item*item*k;
+       }
+}
+
+// --------------------------------------------------------------------
+
+/** The number of data items processed so far */
+public int getN() { return n; }
+
+// --------------------------------------------------------------------
+
+/** The maximum of the data items */
+public double getMax() { return max; }
+
+// --------------------------------------------------------------------
+
+/** The minimum of the data items */
+public double getMin() { return min; }
+
+// --------------------------------------------------------------------
+
+/** Returns the number of data items whose value equals the maximum. */
+public int getMaxCount() { return countmax; }
+
+// --------------------------------------------------------------------
+
+/** Returns the number of data items whose value equals the minimum. */
+public int getMinCount() { return countmin; }
+
+// --------------------------------------------------------------------
+
+/** The sum of the data items */
+public double getSum() { return sum; }
+
+// --------------------------------------------------------------------
+
+/** The sum of the squares of the data items */
+public double getSqrSum() { return sqrsum; }
+
+// --------------------------------------------------------------------
+
+/** The average of the data items */
+public double getAverage() { return sum/n; }
+
+// --------------------------------------------------------------------
+
+/** The empirical variance of the data items. Guaranteed to be larger or
+equal to 0.0. If due to rounding errors the value becomes negative,
+it returns 0.0.*/
+public double getVar() {
+
+       double var=
+               (((double)n) / (n-1)) * (sqrsum/n - getAverage()*getAverage());
+       return (var>=0.0?var:0.0);
+       // XXX note that we have very little possibility to increase numeric
+       // stability if this class is "greedy", ie, if it has no memory
+       // In a more precise implementation we could delay the calculation of
+       // statistics and store the data in some intelligent structure
+}
+
+// --------------------------------------------------------------------
+
+/** the empirical standard deviation of the data items */
+public double getStD() { return Math.sqrt(getVar()); }
+
+// --------------------------------------------------------------------
+
+/**
+* Prints the following quantities separated by spaces in a single line
+* in this order.
+* Minimum, maximum, number of items, average, variance, number of minimal
+* items, number of maximal items.
+*/
+public String toString() {
+
+       return min+" "+max+" "+n+" "+sum/n+" "+getVar()+" "+
+               countmin+" "+countmax;
+}
+
+}
+
diff --git a/contrib/psg/src/peersim/util/IndexIterator.java b/contrib/psg/src/peersim/util/IndexIterator.java
new file mode 100644 (file)
index 0000000..8d078ab
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * 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.util;
+
+/**
+* This class provides iterations over the set of integers [0...k-1].
+*/
+public interface IndexIterator {
+
+       /**
+       * This resets the iteration. The set of integers will be 0,..,k-1.
+       */
+       public void reset(int k);
+       
+       /**
+       * Returns next index.
+       */
+       public int next();
+
+       /**
+       * Returns true if {@link #next} can be called at least one more time.
+       * Note that {@link #next} can be called k times after {@link #reset}.
+       */
+       public boolean hasNext();
+}
+
diff --git a/contrib/psg/src/peersim/util/LinearIterator.java b/contrib/psg/src/peersim/util/LinearIterator.java
new file mode 100644 (file)
index 0000000..2a1ee36
--- /dev/null
@@ -0,0 +1,108 @@
+/*
+ * 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.util;
+
+import java.util.NoSuchElementException;
+
+/**
+* This class gives the linear order 0,1,etc or alternatively k-1, k-2, etc.,
+* depending on the constructor.
+*/
+public class LinearIterator implements IndexIterator {
+
+
+// ======================= private fields ============================
+// ===================================================================
+
+private final boolean reverse;
+
+private int len = 0;
+
+private int pointer = 0;
+
+
+// ======================= initialization ============================
+// ===================================================================
+
+
+/**
+* Construct an iterator for an empty set of numbers.
+* You have to call {@link #reset} to actually fully initialize the object.
+* The numbers returned by consecutive calls to {@link #next} are 0,1,...
+*/
+public LinearIterator() { reverse=false; }
+
+// -------------------------------------------------------------------
+
+/**
+* Construct an interator for an empty set of numbers.
+* You have to call {@link #reset} to actually fully initialize the object.
+* If parameter is true then the numbers returned by consecutive calls to
+* {@link #next} are k-1,k-2,..., otherwise 0,1,...
+*/
+public LinearIterator( boolean rev ) { reverse=rev; }
+
+
+// ======================= public methods ============================
+// ===================================================================
+
+
+public void reset(int k) {
+       
+       len = k;
+       pointer = (reverse ? len-1 : 0);
+}
+
+// -------------------------------------------------------------------
+
+/**
+* Returns next index. The indices are returned in increasing or decreasing
+* order depending on the parameter given at construction time.
+*/
+public int next() {
+       
+       if( !hasNext() ) throw new NoSuchElementException();
+       
+       return (reverse ? pointer-- : pointer++);
+}
+
+// -------------------------------------------------------------------
+
+public boolean hasNext() { return (reverse ? pointer >= 0 : pointer < len); }
+
+// -------------------------------------------------------------------
+
+/*
+public static void main( String pars[] ) throws Exception {
+       
+       LinearIterator rp = new LinearIterator(pars[0].equals("rev"));
+       
+       int k = Integer.parseInt(pars[1]);
+       rp.reset(k);
+       while(rp.hasNext()) System.out.println(rp.next());
+       
+       System.out.println();
+
+       k = Integer.parseInt(pars[2]);
+       rp.reset(k);
+       while(rp.hasNext()) System.out.println(rp.next());
+       System.out.println(rp.next());
+}
+*/
+}
diff --git a/contrib/psg/src/peersim/util/MedianStats.java b/contrib/psg/src/peersim/util/MedianStats.java
new file mode 100644 (file)
index 0000000..be1e9be
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * 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.util;
+
+import java.util.ArrayList;
+import java.util.Collections;
+
+/**
+ * This class adds the ability to retrieve the median element to the
+ * {@link IncrementalStats} class. Note that this class actually stores all
+ * the elements, so (unlike in its superclass) storage requirements depend
+ * on the number of items processed.
+ * 
+ * @author giampa
+ */
+public class MedianStats extends IncrementalStats
+{
+
+/** Structure to store each entry. */
+private final ArrayList<Double> data=new ArrayList<Double>();
+
+/** Calls {@link #reset}. */
+public MedianStats()
+{
+       reset();
+}
+
+/**
+ * Retrieves the median in the current data collection.
+ * 
+ * @return The current median value.
+ */
+public double getMedian()
+{
+       double result;
+
+       if (data.isEmpty())
+               throw new IllegalStateException("Data vector is empty!");
+
+       // Sort the arraylist
+       Collections.sort(data);
+       if (data.size() % 2 != 0) { // odd number
+               result = data.get(data.size() / 2);
+       } else { // even number:
+               double a = data.get(data.size() / 2);
+               double b = data.get(data.size() / 2 - 1);
+               result = (a + b) / 2;
+       }
+       return result;
+}
+
+public void add(double item, int k)
+{
+       for (int i = 0; i < k; ++i) {
+               super.add(item, 1);
+               data.add(new Double(item));
+       }
+}
+
+public void reset()
+{
+       super.reset();
+       if (data != null)
+               data.clear();
+}
+
+
+public static void main( String[] args ) {
+       MedianStats s = new MedianStats();
+       for(int i=0; i<args.length; i++) s.add(Double.parseDouble(args[i]));
+       System.out.println("Average: "+s.getAverage());
+       System.out.println("Median: "+s.getMedian());
+}
+
+}
diff --git a/contrib/psg/src/peersim/util/MomentStats.java b/contrib/psg/src/peersim/util/MomentStats.java
new file mode 100644 (file)
index 0000000..0a847c3
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * 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.util;
+
+/**
+ * This class provides extended statistical informations about the inspected 
+ * distribution. In particular, it provides functions to compute the skewness
+ * (the 3rd degree moment) and the kurtosis (4th degree moment).
+ *
+ * @author  Gian Paolo Jesi
+ */
+public class MomentStats extends IncrementalStats {
+    
+    private double cubicsum, quadsum; // incremental sums
+    
+    /** Calls {@link #reset} */
+    public MomentStats() {
+       reset();
+    }
+    
+    public void reset() {
+        super.reset();
+        cubicsum = quadsum = 0.0;
+    }
+    
+    public void add(double item, int k) {
+        for(int i=0; i<k; ++i)
+       {
+               super.add(item,1);
+               cubicsum += item * item * item;
+               quadsum += item * cubicsum;
+       }
+    }
+   
+    /** Outputs on a single line the superclass statistics postfixed by the 
+     * current skewness and kurtosis.
+     */
+    public String toString() {
+        return super.toString()+" "+getSkewness()+" "+getKurtosis();
+    }
+    
+    /** Computes the skewness on the node values distribution and 
+     * returns the asymmetry coefficient. It gives an indication about the 
+     * distribution symmetry compared to the average.
+     *
+     *@return The skewness value as a double.
+     */ 
+    public double getSkewness() {
+        int n = this.getN();
+        double m3 = (((double)n) / (n-1)) * (cubicsum/n - Math.pow(getAverage(), 3) );
+        return ( m3 / Math.pow(getStD(), 3 ) );
+    }
+    
+    /** Computes the kurtosis on the node values distribution and 
+     *  returns the flatness coefficient. It gives an indication about the 
+     *  distribution sharpness or flatness.
+     *
+     * @return The kurtosis momentus value as a double.
+     */ 
+    public double getKurtosis(){
+        int n = this.getN();
+        double m4 = (((double)n) / (n-1)) * (quadsum/n - Math.pow(getAverage(), 4) );
+        return ( m4 / Math.pow(getStD(), 4) )-3;
+    }
+
+}
diff --git a/contrib/psg/src/peersim/util/RandPermutation.java b/contrib/psg/src/peersim/util/RandPermutation.java
new file mode 100644 (file)
index 0000000..be97ab3
--- /dev/null
@@ -0,0 +1,178 @@
+/*
+ * 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.util;
+
+import java.util.NoSuchElementException;
+import java.util.Random;
+
+/**
+* This class provides a random permutation of indexes. Useful for
+* random sampling without replacement.
+*/
+public class RandPermutation implements IndexIterator {
+
+
+// ======================= private fields ============================
+// ===================================================================
+
+
+private int[] buffer = null;
+
+private int len = 0;
+
+private int pointer = 0;
+
+private final Random r;
+
+
+// ======================= initialization ============================
+// ===================================================================
+
+
+/** Sets source of randomness to be used. You need to call
+* {@link #reset} to fully initialize the object.
+* @param r Source of randomness
+*/
+public RandPermutation( Random r ) { this.r=r; }
+
+// -------------------------------------------------------------------
+
+/** Sets source of randomness and initial size. It calls 
+* {@link #setPermutation} to fully initialize the object with a
+* permuation ready to use. 
+* @param r Source of randomness
+* @param k size of permutation
+*/
+public RandPermutation( int k, Random r ) {
+       
+       this.r=r;
+       setPermutation(k);
+}
+
+
+// ======================= public methods ============================
+// ===================================================================
+
+
+/**
+* It calculates a random permutation of the integers from 0 to k-1.
+* The permutation can be read using method {@link #get}. 
+* If the previous permutation was of the same length, it is more efficient.
+* Note that after calling this the object is reset, so {@link #next} can
+* be called k times, even if {@link #get} was called an arbitrary number of
+* times. Note however that mixing {@link #get} and {@link #next} results in
+* incorrect behavior for {@link #get} (but {@link #next} works fine).
+* The idea is to use this method only in connection with {@link #get}.
+*/
+public void setPermutation(int k) {
+       
+       reset(k);
+       
+       for(int i=len; i>1; i--)
+       {
+               int j = r.nextInt(i);
+               int a = buffer[j];
+               buffer[j] = buffer[i-1];
+               buffer[i-1] = a;
+       }
+}
+
+// -------------------------------------------------------------------
+
+/**
+* Returns the ith element of the permutation set by {@link #setPermutation}.
+* If {@link #next} is called after {@link #setPermutation} and before
+* this method, then the behavior of this method is unspecified.
+*/
+public int get(int i) {
+       
+       if( i >= len ) throw new IndexOutOfBoundsException();
+       return buffer[i];
+}
+
+// -------------------------------------------------------------------
+
+/**
+* It initiates a random permutation of the integers from 0 to k-1.
+* It does not actually calculate the permutation.
+* The permutation can be read using method {@link #next}.
+* Calls to {@link #get} return undefined values, so {@link #next} must be used.
+* If the previous permutation was of the same length, it is more efficient.
+*/
+public void reset(int k) {
+       
+       pointer = k;
+       if( len == k ) return;
+       
+       if( buffer == null || buffer.length < k )
+       {
+               buffer = new int[k];
+       }
+       
+       len = k;
+       for( int i=0; i<len; ++i ) buffer[i]=i;
+}
+
+// -------------------------------------------------------------------
+
+/** Next random sample without replacement */
+public int next() {
+       
+       if( pointer < 1 ) throw new NoSuchElementException();
+       
+       int j = r.nextInt(pointer);
+       int a = buffer[j];
+       buffer[j] = buffer[pointer-1];
+       buffer[pointer-1] = a;
+       
+       return buffer[--pointer];
+}
+
+// -------------------------------------------------------------------
+
+public boolean hasNext() { return pointer > 0; }
+
+// -------------------------------------------------------------------
+
+/*
+public static void main( String pars[] ) throws Exception {
+       
+       RandPermutation rp = new RandPermutation(new Random());
+
+       int k;
+       
+       k = Integer.parseInt(pars[0]);
+       rp.setPermutation(k);
+       for(int i=0; i<k; ++i) System.out.println(rp.get(i));
+
+       System.out.println();
+
+       k = Integer.parseInt(pars[1]);
+       rp.reset(k);
+       while(rp.hasNext()) System.out.println(rp.next());
+       
+       System.out.println();
+
+       k = Integer.parseInt(pars[2]);
+       rp.reset(k);
+       while(rp.hasNext()) System.out.println(rp.next());
+       System.out.println(rp.next());
+}
+*/
+}
diff --git a/contrib/psg/src/peersim/util/StringListParser.java b/contrib/psg/src/peersim/util/StringListParser.java
new file mode 100644 (file)
index 0000000..445e19f
--- /dev/null
@@ -0,0 +1,164 @@
+/*
+ * 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.util;
+
+import java.math.*;
+import java.util.*;
+
+import org.lsmp.djep.groupJep.*;
+
+import peersim.config.*;
+
+/**
+ * This utility class can be used to parse range expressions. In particular,
+ * it is used by {@link peersim.rangesim.RangeSimulator} to express ranges for
+ * configuration properties.
+ * <p>
+ * The language for range expression is the following: 
+ * <pre>
+ *   [rangelist] := [range] | [range],[rangelist]
+ *   [range] := value | min:max | min:max|step | 
+ *      min:max*|step
+ * </pre>
+ * where <tt>value</tt>, <tt>min</tt>, <tt>max</tt> and <tt>step</tt>
+ * are numeric atoms that defines ranges.
+ * <p>
+ * For example, the following range expression:
+ * <pre>
+ *   5,9:11,13:17|2,32:128*|2
+ * </pre>
+ * corresponds to 5 (single value), 9-10-11 (range between 9 and 11,
+ * default increment 1), 13-15-17 (range between 13 and 17, specified
+ * step 2, 32-64-128 (range between 32 and 128, multiplicative step 2).
+ * 
+ * @author Alberto Montresor
+ * @version $Revision: 1.8 $
+ */
+public class StringListParser
+{
+
+/** Disable instance construction */
+private StringListParser() { }
+
+/**
+ * Parse the specified string.
+ * 
+ * @param s the string to be parsed
+ * @return an array of strings containing all the values defined by the
+ *   range string
+ */
+public static String[] parseList(String s)
+{
+       ArrayList<String> list = new ArrayList<String>();
+       String[] tokens = s.split(",");
+       for (int i = 0; i < tokens.length; i++) {
+               parseItem(list, tokens[i]);
+       }
+       return list.toArray(new String[list.size()]);
+}
+
+private static void parseItem(List<String> list, String item)
+{
+       String[] array = item.split(":");
+       if (array.length == 1) {
+               parseSingleItem(list, item);
+       } else if (array.length == 2) {
+               parseRangeItem(list, array[0], array[1]);
+       } else {
+               throw new IllegalArgumentException("Element " + item
+                               + "should be formatted as <start>:<stop> or <value>");
+       }
+}
+
+private static void parseSingleItem(List<String> list, String item)
+{
+       list.add(item);
+}
+
+private static void parseRangeItem(List<String> list, String start, String stop)
+{
+       Number vstart;
+       Number vstop;
+       Number vinc;
+       boolean sum;
+       
+       GroupJep jep = new GroupJep(new Operators());
+       jep.parseExpression(start);
+       vstart = (Number) jep.getValueAsObject(); 
+       int pos = stop.indexOf("|*");
+       if (pos >= 0) {
+               // The string contains a multiplicative factor
+               jep.parseExpression(stop.substring(0, pos));
+               vstop = (Number) jep.getValueAsObject(); 
+               jep.parseExpression(stop.substring(pos + 2));
+               vinc = (Number) jep.getValueAsObject(); 
+               sum = false;
+       } else {
+               pos = stop.indexOf("|");
+               // The string contains an additive factor
+               if (pos >= 0) {
+                       // The string contains just the final value
+                       jep.parseExpression(stop.substring(0, pos));
+                       vstop = (Number) jep.getValueAsObject(); 
+                       jep.parseExpression(stop.substring(pos + 1));
+                       vinc = (Number) jep.getValueAsObject(); 
+                       sum = true;
+               } else {
+                       jep.parseExpression(stop);
+                       vstop = (Number) jep.getValueAsObject(); 
+                       vinc = BigInteger.ONE;
+                       sum = true;
+               }
+       }
+       
+       if (vstart instanceof BigInteger && vstart instanceof BigInteger && vinc instanceof BigInteger) {
+               long vvstart = vstart.longValue();
+               long vvstop  =  vstop.longValue();
+               long vvinc   =   vinc.longValue(); 
+               if (sum) {
+                       for (long i = vvstart; i <= vvstop; i += vvinc)
+                               list.add("" + i);
+               } else {
+                       for (long i = vvstart; i <= vvstop; i *= vvinc)
+                               list.add("" + i);
+               }
+       } else {
+               double vvstart = vstart.doubleValue();
+               double vvstop  =  vstop.doubleValue();
+               double vvinc   =   vinc.doubleValue(); 
+               if (sum) {
+                       for (double i = vvstart; i <= vvstop; i += vvinc) 
+                               list.add("" + i);
+               } else {
+                       for (double i = vvstart; i <= vvstop; i *= vvinc)
+                               list.add("" + i);
+               }
+       }
+}
+
+/*
+public static void main(String[] args)
+{
+       String[] ret = parseList(args[0]);
+       for (int i = 0; i < ret.length; i++)
+               System.out.print(ret[i] + " ");
+       System.out.println("");
+}
+*/
+}
diff --git a/contrib/psg/src/peersim/util/WeightedRandPerm.java b/contrib/psg/src/peersim/util/WeightedRandPerm.java
new file mode 100644 (file)
index 0000000..80c8928
--- /dev/null
@@ -0,0 +1,194 @@
+/*
+ * 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.util;
+
+import java.util.NoSuchElementException;
+import java.util.Random;
+
+/**
+* This class provides a weighted random permutation of indexes.
+* Useful for weighted random sampling without replacement.
+* The next sample is taken according to the weights given as a parameter
+* to {@link #reset(int)}.
+* The weights work as follows.
+* The first sample is drawn according to the probability distribution
+* defined by the (normalized) weights.
+* After this the remaining k-1 elements and the associated k-1
+* (re-normalized) weights
+* define a new probability distribution, according to which the 2nd element
+* is drawn, and so on.
+*/
+public class WeightedRandPerm implements IndexIterator {
+
+
+// ======================= private fields ============================
+// ===================================================================
+
+/** Holds the weights that are used to initialize the permutation */
+private final double[] w;
+
+/** Holds the sum of the weights until the given index, inclusive. */
+private final double[] wsum;
+
+private int[] buffer = null;
+
+/** Working array for calculating the permutation */ 
+private double[] weights = null;
+
+private int len = 0;
+
+private int pointer = 0;
+
+private double sum = 0.0;
+
+private final Random r;
+
+
+// ======================= initialization ============================
+// ===================================================================
+
+
+/** Set the source of randomness to use and the weights. You need to call
+* {@link #reset} to fully initialize the object.
+* @param r source of randomness
+* @param weights The array that holds the weights for the calculation of the
+* permutation. The length of the array will be an upper bound on the
+* parameter {@link #reset} accepts. If {@link #reset} is called with a
+* parameter less than the length of weights, the prefix of the same length
+* is used.
+* The vector elements must be positive, that is, zero is not accepted either.
+*/
+public WeightedRandPerm( Random r, double[] weights ) {
+
+       this.r=r;
+       w = weights.clone();
+       wsum = weights.clone();;
+       this.weights = new double[w.length];
+       buffer = new int[w.length];
+       
+       for(int i=0; i<w.length; ++i)
+       {
+               if( w[i] <= 0.0 ) throw new IllegalArgumentException(
+                       "weights should be positive: w["+i+"]="+w[i]);
+       }
+       
+       for(int i=1; i<w.length; ++i) wsum[i]+=wsum[i-1];
+}
+
+
+// ======================= public methods ============================
+// ===================================================================
+
+
+/**
+* It initiates a random weighted permutation of the integeres from 0 to k-1.
+* It does not actually calculate the permutation.
+* The permutation can be read using method {@link #next}.
+* If the previous permutation was of the same length, it is more efficient.
+* The weights set at construction time work as follows.
+* The first sample is drawn according to the probability distribution
+* defined by the (normalized) weights.
+* After this the remaining k-1 elements and the associated k-1
+* (re-normalized) weights
+* define a new probability distribution, according to which the 2nd element
+* is drawn, and so on.
+* @param k the set is defined as 0,...,k-1
+*/
+public void reset(int k) {
+       
+       if( k<0 || k>w.length )
+               throw new IllegalArgumentException(
+                       "k should be non-negative and <= "+w.length);
+       
+       pointer = k;
+       sum = wsum[k-1];
+       
+       if( k != len )
+       {
+               // we need to initialize weights and buffer
+               for(int i=0; i<k; ++i)
+               {
+                       weights[i]=w[i];
+                       buffer[i]=i;
+               }
+               len=k;
+       }
+}
+
+// -------------------------------------------------------------------
+
+/**
+* The first sample is drawn according to the probability distribution
+* defined by the (normalized) weights.
+* After this the remaining k-1 elements and the associated k-1
+* (re-normalized) weights
+* define a new probability distribution, according to which the 2nd element
+* is drawn, and so on.
+* @see #reset
+*/
+public int next() {
+       
+       if( pointer < 1 ) throw new NoSuchElementException();
+       
+       double d = sum*r.nextDouble();
+       int i = pointer;
+       double tmp = weights[i-1];
+       while( tmp < d && i>1 ) tmp += weights[--i-1];
+       
+       // now i-1 is the selected element, we shift it to next position
+       int a = buffer[i-1];
+       double b = weights[i-1];
+       buffer[i-1] = buffer[pointer-1];
+       weights[i-1] = weights[pointer-1];
+       buffer[pointer-1] = a;
+       weights[pointer-1] = b;
+       sum -= b;
+       
+       return buffer[--pointer];
+}
+
+// -------------------------------------------------------------------
+
+public boolean hasNext() { return pointer > 0; }
+
+// -------------------------------------------------------------------
+
+/*
+public static void main( String pars[] ) throws Exception {
+       
+
+       int k = pars.length;
+       double w[] = new double[k];
+       for(int i=0; i<k; ++i) w[i] = Double.parseDouble(pars[i]);
+       
+       WeightedRandPerm rp = new WeightedRandPerm(new Random(),w);
+       rp.reset(k);
+       for(int i=0; i<1000; ++i)
+       {
+               if(i%2==0) rp.reset(k);
+               if(i%2==1) rp.reset(k-1);
+               while(rp.hasNext()) System.out.print(rp.next()+" ");
+               System.out.println();
+       }
+       
+       System.out.println();
+}
+*/
+}
+
diff --git a/contrib/psg/src/peersim/vector/Getter.java b/contrib/psg/src/peersim/vector/Getter.java
new file mode 100644 (file)
index 0000000..a90e756
--- /dev/null
@@ -0,0 +1,237 @@
+/*
+ * 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.vector;
+
+import java.lang.reflect.*;
+import peersim.config.*;
+import peersim.core.*;
+
+/**
+ * Vectors can be written through this class. Typically {@link Control} classes
+ * use this to manipulate vectors.
+ * <p>
+ * The method to be used is specified at construction time.
+ * For backward compatibility, if no method is specified, the method
+ * <code>getValue</code> is used. In this way, protocols
+ * implementing the {@link SingleValue} interface can be manipulated using the
+ * old configuration syntax (i.e., without specifying the method).
+ * <p>
+ * Please refer to package {@link peersim.vector} for a detailed description of 
+ * the concept of protocol vector and the role of getters and setters. 
+ */
+public class Getter {
+
+// ============================ fields ===================================
+// =======================================================================
+
+private final String protocol;
+private final String methodn;
+private final String prefix;
+
+/** Identifier of the protocol that defines the vector */
+private int pid;
+
+/** Getter method name */
+private String methodName;
+
+/** Getter method */
+private Method method = null;
+
+/** Parameter type of getter method */
+private Class type;
+
+
+// ========================== initialization =============================
+// =======================================================================
+
+
+/**
+ * Constructs a Getter class based on the configuration. Note that the
+ * actual initialization is delayed until the first access to the class,
+ * so that if a class is not used, no unnecessary error messages and exceptions
+ * are generated.
+ * @param prefix the configuration prefix to use when reading the configuration
+ * @param protocol the configuration parameter name that contains
+ * the protocol we want to manipulate using a getter method.
+ * The parameter <code>prefix + "." + protocol</code> is read.
+ * @param methodn the configuration parameter name that contains the getter
+ * method name.
+ * The parameter <code>prefix + "." + methodn</code> is read, with the default
+ * value <code>getValue</code>.
+ */
+public Getter(String prefix, String protocol, String methodn) {
+
+       this.prefix=prefix;
+       this.protocol=protocol;
+       this.methodn=methodn;
+}
+
+// --------------------------------------------------------------------------
+
+/** Performs actual initialization */
+private void init() {
+
+       if( method!=null) return;
+
+       // Read configuration parameter
+       pid = Configuration.getPid(prefix + "." + protocol);
+       methodName = Configuration.getString(prefix+"."+methodn,"getValue");
+       // Search the method
+       Class clazz = Network.prototype.getProtocol(pid).getClass();
+       try {
+               method = GetterSetterFinder.getGetterMethod(clazz, methodName);
+       } catch (NoSuchMethodException e) {
+               throw new IllegalParameterException(prefix + "." +
+               methodn, e+"");
+       }
+       // Obtain the type of the field
+       type = GetterSetterFinder.getGetterType(method);
+}
+
+
+// =============================== methods =============================
+// =====================================================================
+
+/**
+* @return type of return value of getter method
+*/
+public Class getType() {
+
+       init();
+       return type;
+}
+
+// --------------------------------------------------------------------------
+
+/**
+* Gets the given value as a Number.
+* @param n The node to get the value on. The protocol is defined
+* by {@link #pid}.
+* @return the read value.
+*/
+public Number get(Node n) {
+       
+       init();
+
+       try 
+       {
+               Object ret =method.invoke(n.getProtocol(pid));
+               if (ret instanceof Boolean)
+                       return ((Boolean) ret) ? 1 : 0;
+               else
+                       return (Number) ret;
+       }
+       catch (Exception e)
+       {
+               throw new RuntimeException("While using getter "+methodName,e);
+       }
+}
+
+// --------------------------------------------------------------------------
+
+/**
+* Gets the given integer value.
+* @param n The node to get the value on. The protocol is defined
+* by {@link #pid}.
+* @return the read value.
+*/
+public long getLong(Node n) {
+       
+       init();
+
+       if(type==long.class || type==int.class)
+       {
+               try 
+               {
+                       return ((Number)
+                       method.invoke(n.getProtocol(pid))).longValue();
+               }
+               catch (Exception e)
+               {
+                       throw new RuntimeException(
+                       "While using getter "+methodName,e);
+               }
+       }       
+       else throw new RuntimeException("type has to be int or long");
+}
+
+// --------------------------------------------------------------------------
+
+/**
+* Gets the given real value.
+* @param n The node to get the value on. The protocol is defined
+* by {@link #pid}.
+* @return the read value.
+*/
+public double getDouble(Node n) {
+       
+       init();
+
+       if(type==double.class || type==float.class)
+       {
+               try
+               {
+                       return ((Number)
+                       method.invoke(n.getProtocol(pid))).doubleValue();
+               }
+               catch (Exception e)
+               {
+                       throw new RuntimeException(
+                       "While using getter "+methodName,e);
+               }
+       }
+       else throw new RuntimeException(
+                       "type has to be double or float");
+}
+
+// --------------------------------------------------------------------------
+
+/**
+* Gets the given value as a Number.
+* @param i The index of the node to get the value on in the network.
+* The protocol is defined
+* by {@link #pid}.
+* @return the read value.
+*/
+public Number get(int i) { return get(Network.get(i)); }
+
+// --------------------------------------------------------------------------
+
+/**
+* Gets the given integer value.
+* @param i The index of the node to get the value on in the network.
+* The protocol is defined
+* by {@link #pid}.
+* @return the read value.
+*/
+public long getLong(int i) { return getLong(Network.get(i)); }
+
+// --------------------------------------------------------------------------
+
+/**
+* Gets the given real value.
+* @param i The index of the node to get the value on in the network.
+* The protocol is defined
+* by {@link #pid}.
+* @return the read value.
+*/
+public double getDouble(int i) { return getDouble(Network.get(i)); }
+
+}
+
diff --git a/contrib/psg/src/peersim/vector/GetterSetterFinder.java b/contrib/psg/src/peersim/vector/GetterSetterFinder.java
new file mode 100644 (file)
index 0000000..48670be
--- /dev/null
@@ -0,0 +1,174 @@
+/*
+ * 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.vector;
+
+import java.lang.reflect.*;
+import java.util.*;
+
+/**
+ * This utility class can be used to obtain get/set methods from classes. In
+ * particular, it is used in the vector package to locate get/set methods for
+ * observing and modifying protocol fields.
+ * Please refer to package {@link peersim.vector} for a definition of
+ * getter and setter methods. 
+ */
+class GetterSetterFinder
+{
+
+//--------------------------------------------------------------------------
+
+/**
+ * Search a getter method in the specified class. It succeeds only of there
+ * is exactly one method with the given name that is a getter method.
+ * Please refer to package {@link peersim.vector} for a definition of
+ * getter methods. 
+ * 
+ * @param clazz
+ *          the class where to find get/set method
+ * @param methodName
+ *          the method to be searched
+ * @return the requested method
+ */
+public static Method getGetterMethod(Class clazz, String methodName)
+               throws NoSuchMethodException
+{
+       // Search methods
+       Method[] methods = clazz.getMethods();
+       ArrayList<Method> list = new ArrayList<Method>();
+       for (Method m: methods) {
+               if (m.getName().equals(methodName)) {
+                       list.add(m);
+               }
+       }
+       if (list.size() == 0) {
+               throw new NoSuchMethodException("No getter method for method "
+               + methodName + " in class " + clazz.getName());
+       } else if (list.size() > 1) {
+               throw new NoSuchMethodException("Multiple getter for method "
+               + methodName + " in class " + clazz.getName());
+       }
+       
+       // Found a single method with the right name; check if
+       // it is a gettter.
+       Method method = list.get(0);
+       Class[] pars = method.getParameterTypes();
+       if (pars.length > 0) {
+               throw new NoSuchMethodException(method.getName() + " of class "
+               + clazz.getName()
+               + " is not a valid getter method: "+
+               "its argument list is not empty");
+       }
+       
+       Class ret = method.getReturnType();
+       if (    !( ret==int.class || ret==long.class ||
+               ret==double.class || ret==float.class || ret==boolean.class)
+       ) {
+               throw new NoSuchMethodException(method.getName() + " of class "
+               + clazz.getName() + " is not a valid getter method: "+
+               "it should have a return type of int, long, short or double");
+       }
+       
+       return method;
+}
+
+//--------------------------------------------------------------------------
+
+/**
+ * Search a setter method in the specified class.
+ * It succeeds only of there
+ * is exactly one method with the given name that is a setter method.
+ * Please refer to package {@link peersim.vector} for a definition of
+ * setter methods. 
+ * @param clazz
+ *          the class where to find get/set method
+ * @param methodName
+ *          the method to be searched
+ * @return the requested method, if it fully conforms to the definition of
+ * the setter methods.
+ */
+public static Method getSetterMethod(Class clazz, String methodName)
+               throws NoSuchMethodException
+{
+       // Search methods
+       Method[] methods = clazz.getMethods();
+       ArrayList<Method> list = new ArrayList<Method>();
+       for (Method m: methods) {
+               if (m.getName().equals(methodName)) {
+                       list.add(m);
+               }
+       }
+       
+       if (list.size() == 0) {
+               throw new NoSuchMethodException("No setter method for method "
+               + methodName + " in class " + clazz.getName());
+       } else if (list.size() > 1) {
+               throw new NoSuchMethodException("Multiple setter for method "
+               + methodName + " in class " + clazz.getName());
+       }
+       
+       // Found a single method with the right name; check if
+       // it is a setter.
+       Method method = list.get(0);
+       Class[] pars = method.getParameterTypes();
+       if (    pars.length != 1 ||
+               !( pars[0]==int.class || pars[0]==long.class ||
+               pars[0]==double.class || pars[0]==float.class )
+       ) {
+               throw new NoSuchMethodException(method.getName() + " of class "
+               + clazz.getName()
+               + " is not a valid setter method: "+
+               "it should have exactly one argument of type "+
+               "int, long, short or double");
+       }
+       
+       Class ret = method.getReturnType();
+       if (!ret.equals(void.class)) {
+               throw new NoSuchMethodException(method.getName() + "  of class "
+               + clazz.getName() +
+               " is not a valid setter method; it returns a value");
+       }
+       
+       return method;
+}
+
+//--------------------------------------------------------------------------
+
+
+/**
+ * Returns the field type for the specified getter.
+ */
+public static Class getGetterType(Method m)
+{
+       return m.getReturnType();
+}
+
+//--------------------------------------------------------------------------
+
+/**
+ * Returns the field type for the specified setter.
+ */
+public static Class getSetterType(Method m)
+{
+       Class[] pars = m.getParameterTypes();
+       return pars[0];
+}
+
+//--------------------------------------------------------------------------
+
+}
diff --git a/contrib/psg/src/peersim/vector/InitVectFromFile.java b/contrib/psg/src/peersim/vector/InitVectFromFile.java
new file mode 100644 (file)
index 0000000..1bfaa17
--- /dev/null
@@ -0,0 +1,128 @@
+/*
+ * 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.vector;
+
+import java.io.*;
+import java.util.*;
+import peersim.config.*;
+import peersim.core.*;
+
+/**
+ * Initializes a protocol vector from data read from a file.
+ * The file format is as follows:
+ * lines starting with # or lines that contain only
+ * whitespace are ignored.
+ * From the rest of the lines the first field separated by whitespace is
+ * read. Only the first field is read from each line, the rest of the line
+ * is ignored.
+ * The file can contain more values than necessary but
+ * enough values must be present.
+ * @see VectControl
+ * @see peersim.vector
+ */
+public class InitVectFromFile extends VectControl
+{
+
+// --------------------------------------------------------------------------
+// Parameter names
+// --------------------------------------------------------------------------
+
+/**
+ * The filename to load links from.
+ * @config
+ */
+private static final String PAR_FILE = "file";
+
+// --------------------------------------------------------------------------
+// Fields
+// --------------------------------------------------------------------------
+
+/** The file to be read */
+private final String file;
+
+// --------------------------------------------------------------------------
+// Initialization
+// --------------------------------------------------------------------------
+
+/**
+ * Standard constructor that reads the configuration parameters.
+ * Invoked by the simulation engine.
+ * @param prefix the configuration prefix for this class
+ */
+public InitVectFromFile(String prefix)
+{
+       super(prefix);
+       file = Configuration.getString(prefix + "." + PAR_FILE);
+}
+
+// --------------------------------------------------------------------------
+// Methods
+// --------------------------------------------------------------------------
+
+/**
+ * Initializes values from a file.
+ * The file format is as follows:
+ * lines starting with # or lines that contain only
+ * whitespace are ignored.
+ * From the rest of the lines the first field separated by whitespace is
+ * read. Only the first field is read from each line, the rest of the line
+ * is ignored.
+ * The file can contain more values than necessary but
+ * enough values must be present.
+ * @throws RuntimeException if the file cannot be read or contains too few
+ * values
+ * @return always false
+ */
+public boolean execute() {
+
+       int i = 0;
+
+try {
+       FileReader fr = new FileReader(file);
+       LineNumberReader lnr = new LineNumberReader(fr);
+       String line;
+       while ((line = lnr.readLine()) != null && i < Network.size()) {
+               if (line.startsWith("#"))
+                       continue;
+               StringTokenizer st = new StringTokenizer(line);
+               if (!st.hasMoreTokens())
+                       continue;
+               if( setter.isInteger() )
+                       setter.set(i,Long.parseLong(st.nextToken()));
+               else    setter.set(i,Double.parseDouble(st.nextToken()));
+               i++;
+       }
+       lnr.close();
+}
+catch(IOException e)
+{
+       throw new RuntimeException("Unable to read file: " + e);
+}
+       
+       if (i < Network.size())
+               throw new RuntimeException(
+               "Too few values in file '" + file + "' (only "
+               + i + "); we need " + Network.size() + ".");
+       
+       return false;
+}
+
+// --------------------------------------------------------------------------
+
+}
diff --git a/contrib/psg/src/peersim/vector/LinearDistribution.java b/contrib/psg/src/peersim/vector/LinearDistribution.java
new file mode 100644 (file)
index 0000000..e7cc19e
--- /dev/null
@@ -0,0 +1,123 @@
+/*
+ * 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.vector;
+
+import peersim.config.*;
+import peersim.core.*;
+
+/**
+ * Initializes a protocol vector with values in the range [{@value #PAR_MIN}, 
+ * {@value #PAR_MAX}] (inclusive both ends), linearly increasing.
+ * @see VectControl
+ * @see peersim.vector
+ */
+public class LinearDistribution extends VectControl
+{
+
+//--------------------------------------------------------------------------
+//Parameters
+//--------------------------------------------------------------------------
+
+/**
+ * Upper end of the interval..
+ * @config
+ */
+private static final String PAR_MAX = "max";
+
+/**
+ * Lower end of the interval. Defaults to -{@value #PAR_MAX}.
+ * @config
+ */
+private static final String PAR_MIN = "min";
+
+// --------------------------------------------------------------------------
+// Fields
+// --------------------------------------------------------------------------
+
+/** Minimum value */
+private final Number min;
+
+/** Maximum value */
+private final Number max;
+
+/** Step value */
+private final double step;
+
+// --------------------------------------------------------------------------
+// Initialization
+// --------------------------------------------------------------------------
+
+/**
+ * Standard constructor that reads the configuration parameters.
+ * Invoked by the simulation engine.
+ * @param prefix the configuration prefix for this class
+ */
+public LinearDistribution(String prefix)
+{
+       super(prefix);
+       
+       // Read parameters based on type
+       if (setter.isInteger()) {
+               max=Long.valueOf(Configuration.getLong(prefix + "." + PAR_MAX));
+               min=Long.valueOf(Configuration.getLong(prefix + "." + PAR_MIN, 
+                               -max.longValue()));
+               step= (max.longValue()-min.longValue())/
+                       ((double)(Network.size()-1));
+       } else { // we know it's double or float
+               max = new Double(Configuration.getDouble(prefix+"."+PAR_MAX));
+               min = new Double(Configuration.getDouble(prefix+"."+PAR_MIN, 
+                               -max.doubleValue()));
+               step= (max.doubleValue()-min.doubleValue())/(Network.size()-1);
+       }
+}
+
+// --------------------------------------------------------------------------
+// Methods
+// --------------------------------------------------------------------------
+
+/**
+ * Initializes a protocol vector with values in the range [{@value #PAR_MIN}, 
+ * {@value #PAR_MAX}] (inclusive both ends), linearly increasing.
+ * @return always false
+ */
+public boolean execute() {
+       
+       if ( setter.isInteger() )
+       {
+               for(int i=0; i<Network.size(); ++i)
+               {
+                       // we avoid the entire expression being cast to double
+                       setter.set(i,Math.round(i*step)+min.longValue());
+               }
+       }
+       else
+       {
+               for(int i=0; i<Network.size(); ++i)
+               {
+                       setter.set(i,i*step+min.doubleValue());
+               }
+       }
+
+       return false;
+}
+
+
+}
+
+
diff --git a/contrib/psg/src/peersim/vector/Normalizer.java b/contrib/psg/src/peersim/vector/Normalizer.java
new file mode 100644 (file)
index 0000000..5aa4383
--- /dev/null
@@ -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.vector;
+
+import peersim.config.*;
+import peersim.core.*;
+
+/**
+ * Normalizes the values of a protocol vector.
+ * The normalization is based on the L1 norm, that is, the sum of the
+ * absolute values of the vector elements. Parameter {@value #PAR_L1} defines
+ * the L1 norm that the vector will have after normalization.
+ * @see VectControl
+ * @see peersim.vector
+ */
+public class Normalizer extends VectControl
+{
+
+// --------------------------------------------------------------------------
+// Parameters
+// --------------------------------------------------------------------------
+
+/**
+ * The L1 norm (sum of absolute values) to normalize to. After the operation the
+ * L1 norm will be the value given here. Defaults to 1.
+ * @config
+ */
+private static final String PAR_L1 = "l1";
+
+
+// --------------------------------------------------------------------------
+// Fields
+// --------------------------------------------------------------------------
+
+/** L1 norm */
+private final double l1;
+
+
+// --------------------------------------------------------------------------
+// Initialization
+// --------------------------------------------------------------------------
+
+/**
+ * Standard constructor that reads the configuration parameters.
+ * Invoked by the simulation engine.
+ * @param prefix the configuration prefix for this class
+ */
+public Normalizer(String prefix)
+{
+       super(prefix);
+       l1 = Configuration.getDouble(prefix + "." + PAR_L1, 1);
+       
+       if( setter.isInteger() ) 
+               throw new IllegalParameterException(prefix + "." + PAR_METHOD,
+                       "setter value must be floating point, instead of "+
+                       setter.getType());
+                       
+       if( setter.getType() !=  getter.getType() )
+               throw new IllegalParameterException(prefix + "." + PAR_GETTER,
+               "getter and setter must have the same numeric type, "+
+               "but we have "+setter.getType()+" and "+getter.getType());
+}
+
+//--------------------------------------------------------------------------
+//Methods
+//--------------------------------------------------------------------------
+
+/**
+ * Makes the sum of the absolute values (L1 norm) equal to the value
+ * given in the configuration parameter {@value #PAR_L1}. If the value is
+ * negative, the L1 norm will be the absolute value and the vector elements
+ * change sign.
+ * @return always false
+ */
+public boolean execute() {
+       
+       double sum = 0.0;
+       for (int i = 0; i < Network.size(); ++i)
+       {
+               sum += getter.getDouble(i);
+       }
+       if (sum == 0.0)
+       {
+               throw new
+               RuntimeException("Attempted to normalize all zero vector.");
+       }
+       double factor = l1 / sum;
+       for (int i = 0; i < Network.size(); ++i)
+       {
+               double val = getter.getDouble(i)*factor;
+               setter.set(i,val);
+       }
+       return false;
+}
+
+//--------------------------------------------------------------------------
+
+}
diff --git a/contrib/psg/src/peersim/vector/PeakDistribution.java b/contrib/psg/src/peersim/vector/PeakDistribution.java
new file mode 100644 (file)
index 0000000..c9f1309
--- /dev/null
@@ -0,0 +1,139 @@
+/*
+ * 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.vector;
+
+import peersim.config.*;
+import peersim.core.*;
+
+
+/**
+ * Initializes the values so that {@value #PAR_PEAKS} nodes have value
+ * {@value #PAR_VALUE}/{@value #PAR_PEAKS}, the rest {@value #PAR_LVALUE}
+ * (zero by default).
+ * @see VectControl
+ * @see peersim.vector
+ */
+public class PeakDistribution extends VectControl
+{
+
+// --------------------------------------------------------------------------
+// Parameters
+// --------------------------------------------------------------------------
+
+/** 
+ * The sum of values in the system, to be equally distributed between peak 
+ * nodes.
+ * @config
+ */
+private static final String PAR_VALUE = "value";
+
+/** 
+ * The value for the nodes that are not peaks. This parameter is optional,
+ * by default, the nodes that are
+ * not peaks are set to zero. This value overrides that behavior.
+ * @config
+ */
+private static final String PAR_LVALUE = "background";
+
+/** 
+ * The number of peaks in the system. If this value is greater than or equal to
+ * 1, it is interpreted as the actual number of peaks. If it is included in 
+ * the range [0, 1] it is interpreted as a percentage with respect to the
+ * current network size. Defaults to 1. 
+ * @config
+ */
+private static final String PAR_PEAKS = "peaks";
+
+
+// --------------------------------------------------------------------------
+// Fields
+// --------------------------------------------------------------------------
+
+/** Total load */
+private final Number lvalue;
+
+/** Total load */
+private final Number value;
+
+/** Number of peaks */
+private final double peaks;
+
+// --------------------------------------------------------------------------
+// Initialization
+// --------------------------------------------------------------------------
+
+/**
+ * Standard constructor that reads the configuration parameters.
+ * Invoked by the simulation engine.
+ * @param prefix the configuration prefix for this class
+ */
+public PeakDistribution(String prefix)
+{
+       super(prefix);
+       
+       peaks = Configuration.getDouble(prefix+"."+PAR_PEAKS, 1);
+       
+       if( setter.isInteger() )
+       {
+               value=Long.valueOf(Configuration.getLong(prefix+"."+PAR_VALUE));
+               lvalue=Long.valueOf(Configuration.getLong(prefix+"."+PAR_LVALUE,0));
+       }
+       else
+       {
+               value = new Double(Configuration.getDouble(prefix + "." +
+               PAR_VALUE));
+               lvalue = new Double(Configuration.getDouble(prefix + "." +
+               PAR_LVALUE,0));
+       }
+}
+
+// --------------------------------------------------------------------------
+// Methods
+// --------------------------------------------------------------------------
+
+/**
+ * Initializes the values so that {@value #PAR_PEAKS} nodes have value
+ * {@value #PAR_VALUE}/{@value #PAR_PEAKS}, the rest zero.
+ * @return always false
+ */
+public boolean execute()
+{
+       int pn = (peaks < 1 ? (int) (peaks*Network.size()) : (int) peaks);
+       
+       if( setter.isInteger() )
+       {
+               long v = value.longValue()/pn;
+               long lv = lvalue.longValue();
+               for (int i=0; i < pn; i++) setter.set(i, v);
+               for (int i=pn; i < Network.size(); i++) setter.set(i,lv);
+       }
+       else
+       {
+               double v = value.doubleValue()/pn;
+               double lv = lvalue.doubleValue();
+               for (int i=0; i < pn; i++) setter.set(i, v);
+               for (int i=pn; i < Network.size(); i++) setter.set(i,lv);
+       }
+
+       return false;
+}
+
+// --------------------------------------------------------------------------
+
+}
diff --git a/contrib/psg/src/peersim/vector/Setter.java b/contrib/psg/src/peersim/vector/Setter.java
new file mode 100644 (file)
index 0000000..cfcf54c
--- /dev/null
@@ -0,0 +1,222 @@
+/*
+ * 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.vector;
+
+import java.lang.reflect.*;
+import peersim.config.*;
+import peersim.core.*;
+
+/**
+ * Vectors can be written through this class. Typically {@link Control} classes
+ * use this to manipulate vectors.
+ * <p>
+ * The method to be used is specified at construction time.
+ * For backward compatibility, if no method is specified, the method
+ * <code>setValue</code> is used. In this way, protocols
+ * implementing the {@link SingleValue} interface can be manipulated using the
+ * old configuration syntax (i.e., without specifying the method).
+ * <p>
+ * Please refer to package {@link peersim.vector} for a detailed description of 
+ * the concept of protocol vector and the role of getters and setters. 
+ */
+public class Setter {
+
+// ============================ fields ===================================
+// =======================================================================
+
+private final String protocol;
+private final String methodn;
+private final String prefix;
+
+/** Identifier of the protocol that defines the vector */
+private int pid;
+
+/** Setter method name */
+private String methodName;
+
+/** Setter method */
+private Method method=null;
+
+/** Parameter type of setter method */
+private Class type;
+
+
+// ========================== initialization =============================
+// =======================================================================
+
+
+/**
+ * Constructs a Setter class based on the configuration.
+ * Note that the
+ * actual initialization is delayed until the first access to the class,
+ * so that if a class is not used, no unnecessary error messages and exceptions
+ * are generated.
+ * @param prefix the configuration prefix to use when reading the configuration
+ * @param protocol the configuration parameter name that contains
+ * the protocol we want to manipulate using a setter method.
+ * The parameter <code>prefix + "." + protocol</code> is read.
+ * @param methodn the configuration parameter name that contains the setter
+ * method name.
+ * The parameter <code>prefix + "." + methodn</code> is read, with the default
+ * value <code>setValue</code>.
+ */
+public Setter(String prefix, String protocol, String methodn) {
+       
+       this.prefix=prefix;
+       this.protocol=protocol;
+       this.methodn=methodn;
+}
+
+// --------------------------------------------------------------------------
+
+private void init() {
+
+       if( method!=null) return;
+
+       // Read configuration parameter
+       pid = Configuration.getPid(prefix + "." + protocol);
+       methodName = Configuration.getString(prefix+"."+methodn,"setValue");
+       // Search the method
+       Class clazz = Network.prototype.getProtocol(pid).getClass();
+       try {
+               method = GetterSetterFinder.getSetterMethod(clazz, methodName);
+       } catch (NoSuchMethodException e) {
+               throw new IllegalParameterException(prefix + "." +
+               methodn, e+"");
+       }
+       // Obtain the type of the field
+       type = GetterSetterFinder.getSetterType(method);
+}
+
+
+// =============================== methods =============================
+// =====================================================================
+
+
+/**
+* @return type of parameter of setter method
+*/
+public Class getType() {
+
+       init();
+       return type;
+}
+
+// --------------------------------------------------------------------------
+
+/**
+* @return true if the setter type is long or int
+*/
+public boolean isInteger() {
+
+       init();
+       return type==long.class || type==int.class;
+}
+
+// --------------------------------------------------------------------------
+
+/**
+* Sets the given integer value.
+* @param n The node to set the value on. The protocol is defined
+* by {@link #pid}.
+* @param val the value to set.
+*/
+public void set(Node n, long val) {
+       
+       init();
+       
+       try 
+       {
+               if(type==long.class)
+               {
+                       method.invoke(n.getProtocol(pid),val);
+                       return;
+               }
+               if(type==int.class)
+               {
+                       method.invoke(n.getProtocol(pid),(int)val);
+                       return;
+               }
+       }
+       catch (Exception e)
+       {
+               throw new RuntimeException("While using setter "+methodName,e);
+               
+       }
+       
+       throw new RuntimeException("type has to be int or long");
+}
+
+// --------------------------------------------------------------------------
+
+/**
+* Sets the given real value.
+* @param n The node to set the value on. The protocol is defined
+* by {@link #pid}.
+* @param val the value to set.
+*/
+public void set(Node n, double val) {
+       
+       init();
+       
+       try
+       {
+               if(type==double.class)
+               {
+                       method.invoke(n.getProtocol(pid),val);
+                       return;
+               }
+               if(type==float.class)
+               {
+                       method.invoke(n.getProtocol(pid),(float)val);
+                       return;
+               }
+       }
+       catch (Exception e)
+       {
+               throw new RuntimeException("While using setter "+methodName,e);
+       }
+       
+       throw new RuntimeException("type has to be double or float");
+}
+
+// --------------------------------------------------------------------------
+
+/**
+* Sets the given integer value.
+* @param i The index of the node to set the value on in the network.
+* The protocol is defined
+* by {@link #pid}.
+* @param val the value to set.
+*/
+public void set(int i, long val) { set(Network.get(i),val); }
+
+// --------------------------------------------------------------------------
+
+/**
+* Sets the given real value.
+* @param i The index of the node to set the value on in the network.
+* The protocol is defined
+* by {@link #pid}.
+* @param val the value to set.
+*/
+public void set(int i, double val) { set(Network.get(i),val); }
+
+}
+
diff --git a/contrib/psg/src/peersim/vector/SingleValue.java b/contrib/psg/src/peersim/vector/SingleValue.java
new file mode 100644 (file)
index 0000000..8d3dd9e
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * 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.vector;
+
+/**
+* The implementor class has a single parameter. This interface
+* provides access to that parameter.
+*/
+public interface SingleValue {
+
+/**
+ * Returns the value of the parameter hold by the implementor
+ * of this interface. 
+ */
+public double getValue();
+
+/**
+ * Modifies the value of the parameter hold by the implementor
+ * of this interface. 
+ */
+public void setValue(double value);
+
+}
+
diff --git a/contrib/psg/src/peersim/vector/SingleValueComparator.java b/contrib/psg/src/peersim/vector/SingleValueComparator.java
new file mode 100644 (file)
index 0000000..0fa324e
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * 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.vector;
+
+import peersim.core.*;
+import java.util.*;
+
+/**
+ * This comparator class compares two node objects based on the value 
+ * maintained by one of its protocols. The protocol must implement the
+ * {@link SingleValue} interface; its identifier has to be specified when a
+ * new comparator is built.
+ *
+ * @author Alberto Montresor
+ * @version $Revision: 1.4 $
+ */
+public class SingleValueComparator implements Comparator 
+{
+
+/** Protocol to be be compared */
+private int pid;
+
+/**
+ * Builds a new comparator that compares the double values maintained
+ * by protocol identified by <code>pid</code>.
+ */
+public SingleValueComparator(int pid) { this.pid = pid; }
+
+/**
+ * Compares the values of two protocols. The parameters must have dynamic type
+ * {@link Node}. The protocol {@link #pid} is accessed on both nodes. These
+ * protocols have to implement the {@link SingleValue} interface. The values
+ * held by these protocol instances are then compared.
+ */
+public int compare(Object o1, Object o2)
+{
+       SingleValue s1 = (SingleValue) ((Node) o1).getProtocol(pid);
+       SingleValue s2 = (SingleValue) ((Node) o2).getProtocol(pid);
+       return (int) (s1.getValue() - s2.getValue());
+}
+       
+}
diff --git a/contrib/psg/src/peersim/vector/SingleValueHolder.java b/contrib/psg/src/peersim/vector/SingleValueHolder.java
new file mode 100644 (file)
index 0000000..450086d
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ * 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.vector;
+
+import peersim.core.*;
+
+/**
+ * The task of this protocol is to store a single double value and make it
+ * available through the {@link SingleValue} interface.
+ *
+ * @author Alberto Montresor
+ * @version $Revision: 1.6 $
+ */
+public class SingleValueHolder 
+implements SingleValue, Protocol
+{
+
+//--------------------------------------------------------------------------
+//Fields
+//--------------------------------------------------------------------------
+       
+/** Value held by this protocol */
+protected double value;
+       
+
+//--------------------------------------------------------------------------
+//Initialization
+//--------------------------------------------------------------------------
+
+/**
+ * Does nothing.
+ */
+public SingleValueHolder(String prefix)
+{
+}
+
+//--------------------------------------------------------------------------
+
+/**
+ * Clones the value holder.
+ */
+public Object clone()
+{
+       SingleValueHolder svh=null;
+       try { svh=(SingleValueHolder)super.clone(); }
+       catch( CloneNotSupportedException e ) {} // never happens
+       return svh;
+}
+
+//--------------------------------------------------------------------------
+//methods
+//--------------------------------------------------------------------------
+
+/**
+ * @inheritDoc
+ */
+public double getValue()
+{
+       return value;
+}
+
+//--------------------------------------------------------------------------
+
+/**
+ * @inheritDoc
+ */
+public void setValue(double value)
+{
+       this.value = value;
+}
+
+//--------------------------------------------------------------------------
+
+/**
+ * Returns the value as a string.
+ */
+public String toString() { return ""+value; }
+
+}
diff --git a/contrib/psg/src/peersim/vector/SingleValueObserver.java b/contrib/psg/src/peersim/vector/SingleValueObserver.java
new file mode 100644 (file)
index 0000000..262d2e0
--- /dev/null
@@ -0,0 +1,124 @@
+/*
+ * 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.vector;
+
+import peersim.config.*;
+import peersim.core.*;
+import peersim.util.*;
+
+/**
+* Print statistics over a vector. The vector is defined by a protocol,
+* specified by {@value #PAR_PROT}, that has to  implement
+* {@link SingleValue}.
+* Statistics printed are: min, max, number of samples, average, variance,
+* number of minimal instances, number of maximal instances (using
+* {@link IncrementalStats#toString}).
+* @see IncrementalStats
+*/
+public class SingleValueObserver implements Control {
+
+
+//--------------------------------------------------------------------------
+//Parameters
+//--------------------------------------------------------------------------
+
+/** 
+ *  The parameter used to determine the accuracy
+ *  (standard deviation) before stopping the simulation. If not 
+ *  defined, a negative value is used which makes sure the observer 
+ *  does not stop the simulation.
+ * @see #execute
+ *  @config
+ */
+private static final String PAR_ACCURACY = "accuracy";
+
+/**
+ * The protocol to operate on.
+ * @config
+ */
+private static final String PAR_PROT = "protocol";
+
+
+//--------------------------------------------------------------------------
+// Fields
+//--------------------------------------------------------------------------
+
+/** The name of this observer in the configuration */
+private final String name;
+
+/** Accuracy for standard deviation used to stop the simulation */
+private final double accuracy;
+
+/** Protocol identifier */
+private final int pid;
+
+
+//--------------------------------------------------------------------------
+// Constructor
+//--------------------------------------------------------------------------
+
+/**
+ * Standard constructor that reads the configuration parameters.
+ * Invoked by the simulation engine.
+ * @param name the configuration prefix for this class
+ */
+public SingleValueObserver(String name)
+{
+       this.name = name;
+       accuracy = Configuration.getDouble(name + "." + PAR_ACCURACY, -1);
+       pid = Configuration.getPid(name + "." + PAR_PROT);
+}
+
+
+//--------------------------------------------------------------------------
+// Methods
+//--------------------------------------------------------------------------
+
+/**
+* Print statistics over a vector. The vector is defined by a protocol,
+* specified by {@value #PAR_PROT}, that has to  implement
+* {@link SingleValue}.
+* Statistics printed are: min, max, number of samples, average, variance,
+* number of minimal instances, number of maximal instances (using 
+* {@link IncrementalStats#toString}).
+* @return true if the standard deviation is below the value of
+ * {@value #PAR_ACCURACY}, and the time of the simulation is larger then zero
+ * (i.e. it has started).
+ */
+public boolean execute()
+{
+       IncrementalStats stats = new IncrementalStats();
+       
+       /* Compute max, min, average */
+       for (int i = 0; i < Network.size(); i++)
+       {
+               SingleValue v = (SingleValue)Network.get(i).getProtocol(pid);
+               stats.add( v.getValue() );
+       }
+
+       /* Printing statistics */
+       System.out.println(name+": "+stats);
+
+       /* Terminate if accuracy target is reached */
+       return (stats.getStD()<=accuracy && CommonState.getTime()>0);
+}
+
+//--------------------------------------------------------------------------
+
+}
diff --git a/contrib/psg/src/peersim/vector/TestVectors.java b/contrib/psg/src/peersim/vector/TestVectors.java
new file mode 100644 (file)
index 0000000..f6920cb
--- /dev/null
@@ -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.vector;
+
+
+/**
+ * Do testing the vector package.
+ */
+public class TestVectors extends SingleValueHolder
+{
+
+//--------------------------------------------------------------------------
+//Fields
+//--------------------------------------------------------------------------
+       
+/** Value held by this protocol */
+protected float fvalue;
+
+/** Value held by this protocol */
+protected int ivalue;
+
+/** Value held by this protocol */
+protected long lvalue;
+       
+
+//--------------------------------------------------------------------------
+//Initialization
+//--------------------------------------------------------------------------
+
+/**
+ * Builds a new (not initialized) value holder.
+ * Calls super constructor.
+ */
+public TestVectors(String prefix) { super(prefix); }
+
+//--------------------------------------------------------------------------
+//methods
+//--------------------------------------------------------------------------
+
+/**
+ * 
+ */
+public int getIValue() { return ivalue; }
+
+//--------------------------------------------------------------------------
+
+/**
+ * 
+ */
+public void setIValue(int value) { ivalue = value; }
+
+//--------------------------------------------------------------------------
+
+/**
+ * 
+ */
+public float getFValue() { return fvalue; }
+
+//--------------------------------------------------------------------------
+
+/**
+ * 
+ */
+public void setFValue(float value) { fvalue = value; }
+
+//--------------------------------------------------------------------------
+
+/**
+ * 
+ */
+public long getLValue() { return lvalue; }
+
+//--------------------------------------------------------------------------
+
+/**
+ * 
+ */
+public void setLValue(long value) { lvalue = value; }
+
+//--------------------------------------------------------------------------
+
+/**
+ * Returns the value as a string.
+ */
+public String toString() { return value+" "+fvalue+" "+ivalue+" "+lvalue; }
+
+}
+
diff --git a/contrib/psg/src/peersim/vector/UniformDistribution.java b/contrib/psg/src/peersim/vector/UniformDistribution.java
new file mode 100644 (file)
index 0000000..bd30fb1
--- /dev/null
@@ -0,0 +1,141 @@
+/*
+ * 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.vector;
+
+import peersim.config.*;
+import peersim.core.*;
+import peersim.dynamics.*;
+
+/**
+ * Initializes the values drawing uniform random samples from the range
+ * [{@value #PAR_MIN}, {@value #PAR_MAX}[.
+ * @see VectControl
+ * @see peersim.vector
+ */
+public class UniformDistribution extends VectControl implements NodeInitializer
+{
+
+//--------------------------------------------------------------------------
+//Parameter names
+//--------------------------------------------------------------------------
+
+/**
+ * The upper bound of the uniform random variable, exclusive.
+ * @config
+ */
+private static final String PAR_MAX = "max";
+
+/**
+ * The lower bound of the uniform
+ * random variable, inclusive. Defaults to -{@value #PAR_MAX}.
+ * @config
+ */
+private static final String PAR_MIN = "min";
+
+// --------------------------------------------------------------------------
+// Fields
+// --------------------------------------------------------------------------
+
+/** Minimum value */
+private final Number min;
+
+/** Maximum value */
+private final Number max;
+
+// --------------------------------------------------------------------------
+// Initialization
+// --------------------------------------------------------------------------
+
+/**
+ * Standard constructor that reads the configuration parameters.
+ * Invoked by the simulation engine.
+ * @param prefix the configuration prefix for this class
+ */
+public UniformDistribution(String prefix)
+{
+       super(prefix);
+       
+       // Read parameters based on type
+       if (setter.isInteger()) {
+               max=Long.valueOf(Configuration.getLong(prefix + "." + PAR_MAX));
+               min=Long.valueOf(Configuration.getLong(prefix + "." + PAR_MIN, 
+                               -max.longValue()));
+       } else { // we know it's double or float
+               max = new Double(Configuration.getDouble(prefix+"."+PAR_MAX));
+               min = new Double(Configuration.getDouble(prefix+"."+PAR_MIN, 
+                               -max.doubleValue()));
+       }
+}
+
+// --------------------------------------------------------------------------
+// Methods
+// --------------------------------------------------------------------------
+
+/**
+ * Initializes the values drawing uniform random samples from the range
+ * [{@value #PAR_MIN}, {@value #PAR_MAX}[.
+ * @return always false
+ */
+public boolean execute() {
+
+       if(setter.isInteger())
+       {
+               long d = max.longValue() - min.longValue();
+               for (int i = 0; i < Network.size(); ++i)
+               {
+                       setter.set(i,CommonState.r.nextLong(d)+min.longValue());
+               }
+       }
+       else
+       {
+               double d = max.doubleValue() - min.doubleValue();
+               for (int i = 0; i < Network.size(); ++i)
+               {
+                       setter.set(i,CommonState.r.nextDouble()*d+
+                       min.doubleValue());
+               }
+       }
+
+       return false;
+}
+
+// --------------------------------------------------------------------------
+
+/**
+ * Initializes the value drawing a uniform random sample from the range
+ * [{@value #PAR_MIN}, {@value #PAR_MAX}[.
+ * @param n the node to initialize
+ */
+public void initialize(Node n) {
+
+       if( setter.isInteger() )
+       {
+               long d = max.longValue() - min.longValue();
+               setter.set(n,CommonState.r.nextLong(d) + min.longValue());
+       }
+       else
+       {
+               double d = max.doubleValue() - min.doubleValue();
+               setter.set(n,CommonState.r.nextDouble()*d);
+       }
+}
+
+// --------------------------------------------------------------------------
+
+}
diff --git a/contrib/psg/src/peersim/vector/ValueDumper.java b/contrib/psg/src/peersim/vector/ValueDumper.java
new file mode 100644 (file)
index 0000000..ce6746e
--- /dev/null
@@ -0,0 +1,134 @@
+/*
+ * 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.vector;
+
+import java.io.*;
+
+import peersim.config.*;
+import peersim.core.*;
+import peersim.util.*;
+
+/**
+ * Dump the content of a vector in a file. Each line
+ * represent a single node.
+ * Values are dumped to a file whose name is obtained from a
+ * configurable prefix (set by {@value #PAR_BASENAME}), a number that is
+ * increased before each dump by one, and the extension ".vec".
+ * <p>
+ * This observer class can observe any protocol field containing a 
+ * primitive value, provided that the field is associated with a getter method 
+ * that reads it.
+ * @see VectControl
+ * @see peersim.vector
+ */
+public class ValueDumper extends VectControl {
+
+
+// --------------------------------------------------------------------------
+// Parameter names
+// --------------------------------------------------------------------------
+
+/**
+ * This is the base name of the file where the values are saved. The full name
+ * will be baseName+cycleid+".vec".
+ * @config
+ */
+private static final String PAR_BASENAME = "outf";
+
+// --------------------------------------------------------------------------
+// Fields
+// --------------------------------------------------------------------------
+
+/** Prefix name of this observer */
+private final String prefix;
+
+/** Base name of the file to be written */
+private final String baseName;
+
+private final FileNameGenerator fng;
+
+// --------------------------------------------------------------------------
+// Constructor
+// --------------------------------------------------------------------------
+
+/**
+ * Standard constructor that reads the configuration parameters.
+ * Invoked by the simulation engine.
+ * @param prefix the configuration prefix for this class
+ */
+public ValueDumper(String prefix) {
+
+       super(prefix);
+       this.prefix = prefix;
+       baseName = Configuration.getString(prefix + "." + PAR_BASENAME, null);
+       if(baseName!=null) fng = new FileNameGenerator(baseName,".vec");
+       else fng = null;
+}
+
+// --------------------------------------------------------------------------
+// Methods
+// --------------------------------------------------------------------------
+
+/**
+ * Dump the content of a vector in a file. Each line
+ * represent a single node.
+ * Values are dumped to a file whose name is obtained from a
+ * configurable prefix (set by {@value #PAR_BASENAME}), a number that is
+ * increased before each dump by one, and the extension ".vec".
+ * @return always false
+ * @throws RuntimeException if there is an I/O problem
+ */
+public boolean execute() {
+try
+{
+       System.out.print(prefix + ": ");
+       
+       // initialize output streams
+       if (baseName != null)
+       {
+               String filename = fng.nextCounterName();
+               System.out.println("writing "+filename);
+               PrintStream pstr =
+                       new PrintStream(new FileOutputStream(filename));
+               for (int i = 0; i < Network.size(); ++i)
+               {
+                       pstr.println(getter.get(i));
+               }
+               pstr.close();
+       }
+       else
+       {
+               System.out.println();
+               for (int i = 0; i < Network.size(); ++i)
+               {
+                       System.out.println(getter.get(i));
+               }
+       }
+}
+catch (IOException e)
+{
+       throw new RuntimeException(prefix + ": Unable to write to file: " + e);
+}
+
+       return false;
+}
+
+// ---------------------------------------------------------------------
+
+}
diff --git a/contrib/psg/src/peersim/vector/VectAngle.java b/contrib/psg/src/peersim/vector/VectAngle.java
new file mode 100644 (file)
index 0000000..629a06e
--- /dev/null
@@ -0,0 +1,141 @@
+/*
+ * 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.vector;
+
+import peersim.core.*;
+
+/**
+ * Observes the cosine angle between two vectors. The number which is output is
+ * the inner product divided by the product of the length of the vectors.
+ * All values are converted to double before processing.
+ * <p>
+ * This observer class can observe any protocol field containing a 
+ * primitive value, provided that the field is associated with a getter method 
+ * that reads it.
+ * The methods to be used are specified through parameter {@value #PAR_METHOD1}
+ * and {@value #PAR_METHOD2}.
+ * <p>
+ * Please refer to package {@link peersim.vector} for a detailed description of 
+ * this mechanism. 
+ */
+public class VectAngle implements Control
+{
+
+// --------------------------------------------------------------------------
+// Parameters
+// --------------------------------------------------------------------------
+
+/**
+ * The first protocol to be observed.
+ * @config
+ */
+private static final String PAR_PROT1 = "protocol1";
+
+/**
+ * The second protocol to be observed.
+ * @config
+ */
+private static final String PAR_PROT2 = "protocol2";
+
+/**
+ * The getter method used to obtain the values of the first protocol. 
+ * Defaults to <code>getValue</code> (for backward compatibility with previous 
+ * implementation of this class, that were based on the 
+ * {@link SingleValue} interface).
+ * Refer to the {@linkplain peersim.vector vector package description} for more 
+ * information about getters and setters.
+ * @config
+ */
+private static final String PAR_METHOD1 = "getter1";
+
+/**
+ * The getter method used to obtain the values of the second protocol. 
+ * Defaults to <code>getValue</code> (for backward compatibility with previous 
+ * implementation of this class, that were based on the 
+ * {@link SingleValue} interface).
+ * Refer to the {@linkplain peersim.vector vector package description} for more 
+ * information about getters and setters.
+ * @config
+ */
+private static final String PAR_METHOD2 = "getter2";
+
+// --------------------------------------------------------------------------
+// Fields
+// --------------------------------------------------------------------------
+
+/** The prefix for this observer*/
+private final String name;
+
+private final Getter getter1;
+
+private final Getter getter2;
+
+// --------------------------------------------------------------------------
+// Initialization
+// --------------------------------------------------------------------------
+
+/**
+ * Standard constructor that reads the configuration parameters.
+ * Invoked by the simulation engine.
+ * @param prefix the configuration prefix for this class
+ */
+public VectAngle(String prefix)
+{
+       name = prefix;
+       getter1 = new Getter(prefix,PAR_PROT1,PAR_METHOD1);
+       getter2 = new Getter(prefix,PAR_PROT2,PAR_METHOD2);
+}
+
+// --------------------------------------------------------------------------
+// Methods
+// --------------------------------------------------------------------------
+
+/**
+ * Observes the cosine angle between two vectors. The printed values
+ * are: cosine, Eucledian norm of vect 1, Eucledian norm of vector 2,
+ * angle in radians.
+* @return always false
+*/
+public boolean execute() {
+
+       double sqrsum1 = 0, sqrsum2 = 0, prod = 0;
+       for (int i = 0; i < Network.size(); ++i)
+       {
+               double v1= getter1.get(i).doubleValue();
+               double v2= getter2.get(i).doubleValue();
+               sqrsum1 += v1 * v1;
+               sqrsum2 += v2 * v2;
+               prod += v2 * v1;
+       }
+       
+       double cos = prod / Math.sqrt(sqrsum1) / Math.sqrt(sqrsum2);
+       
+       // deal with numeric errors
+       if( cos > 1 ) cos=1;
+       if( cos < -1 ) cos = -1;
+       
+       System.out.println(name+": " + cos + " "
+                       + Math.sqrt(sqrsum1) + " " + Math.sqrt(sqrsum2) + " "
+                       + Math.acos(cos));
+       return false;
+}
+
+//--------------------------------------------------------------------------
+
+}
diff --git a/contrib/psg/src/peersim/vector/VectControl.java b/contrib/psg/src/peersim/vector/VectControl.java
new file mode 100644 (file)
index 0000000..174b962
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ * 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.vector;
+
+import peersim.core.*;
+
+/**
+ * Serves as an abstract superclass for {@link Control}s that deal
+ * with vectors.
+ * It reads a {@link Setter} to be used by extending classes.
+ */
+public abstract class VectControl implements Control {
+
+
+// --------------------------------------------------------------------------
+// Parameter names
+// --------------------------------------------------------------------------
+
+/**
+ * The protocol to operate on.
+ * @config
+ */
+protected static final String PAR_PROT = "protocol";
+
+/**
+ * The setter method used to set values in the protocol instances. Defaults to
+ * <code>setValue</code>
+ * (for backward compatibility with previous implementation of this
+ * class, that were based on the {@link SingleValue} interface). Refer to the
+ * {@linkplain peersim.vector vector package description} for more
+ * information about getters and setters.
+ * @config
+ */
+protected static final String PAR_METHOD = "setter";
+
+/**
+ * The getter method used to obtain the protocol values. 
+ * Defaults to <code>getValue</code>
+ * (for backward compatibility with previous 
+ * implementation of this class, that were based on the 
+ * {@link SingleValue} interface).
+ * Refer to the {@linkplain peersim.vector vector package description} for more 
+ * information about getters and setters.
+ * @config
+ */
+protected static final String PAR_GETTER = "getter";
+
+// --------------------------------------------------------------------------
+// Fields
+// --------------------------------------------------------------------------
+
+/** The setter to be used to write a vector. */
+protected final Setter setter;
+
+/** The getter to be used to read a vector. */
+protected final Getter getter;
+
+// --------------------------------------------------------------------------
+// Initialization
+// --------------------------------------------------------------------------
+
+/**
+ * Standard constructor that reads the configuration parameters.
+ * Invoked by the simulation engine.
+ * @param prefix the configuration prefix for this class
+ */
+protected VectControl(String prefix)
+{
+       setter = new Setter(prefix,PAR_PROT,PAR_METHOD);
+       getter = new Getter(prefix,PAR_PROT,PAR_GETTER);
+}
+
+}
+
diff --git a/contrib/psg/src/peersim/vector/VectCopy.java b/contrib/psg/src/peersim/vector/VectCopy.java
new file mode 100644 (file)
index 0000000..6d13091
--- /dev/null
@@ -0,0 +1,113 @@
+/*
+ * 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.vector;
+
+import peersim.core.*;
+import peersim.dynamics.*;
+
+/**
+ * Sets values in a protocol vector by copying the values of another 
+ * protocol vector.
+ * The source is defined by {@value #PAR_SOURCE},
+ * and getter method {@value peersim.vector.VectControl#PAR_GETTER}.
+ * <p>
+ * This dynamics class can copy any primitive field in the source
+ * protocol to any primitive field in the destination protocol,
+ * provided that the former field is associated with a getter method,
+ * while the latter is associated with a setter method.
+ * @see VectControl
+ * @see peersim.vector
+ */
+public class VectCopy extends VectControl implements  NodeInitializer {
+
+
+//--------------------------------------------------------------------------
+//Parameters
+//--------------------------------------------------------------------------
+
+/**
+ * The identifier of the protocol to be copied.
+ * The vector values are copied from this vector.
+ * @config
+ */
+private static final String PAR_SOURCE = "source";
+
+
+// --------------------------------------------------------------------------
+// Variables
+// --------------------------------------------------------------------------
+
+/** Source getter */
+private final Getter source;
+
+//--------------------------------------------------------------------------
+//Initialization
+//--------------------------------------------------------------------------
+
+/**
+ * Standard constructor that reads the configuration parameters.
+ * Invoked by the simulation engine.
+ * @param prefix the configuration prefix for this class
+ */
+public VectCopy(String prefix)
+{
+       super(prefix);
+       source = new Getter(prefix,PAR_SOURCE,PAR_GETTER);
+}
+
+//--------------------------------------------------------------------------
+//Method
+//--------------------------------------------------------------------------
+
+/**
+ * Sets values in a protocol vector by copying the values of another 
+ * protocol vector. The source is defined by {@value #PAR_SOURCE},
+ * and getter method {@value peersim.vector.VectControl#PAR_GETTER}.
+ * @return always false
+ */
+public boolean execute() {
+
+       int size = Network.size();
+       for (int i = 0; i < size; i++) {
+               Number ret = source.get(i);
+               if(setter.isInteger()) setter.set(i,ret.longValue());
+               else setter.set(i,ret.doubleValue());
+       }
+
+       return false;
+}
+
+//--------------------------------------------------------------------------
+
+/**
+ * Sets the value by copying the value of another 
+ * protocol. The source is  defined by {@value #PAR_SOURCE},
+ * and getter method {@value peersim.vector.VectControl#PAR_GETTER}.
+ * @param n the node to initialize
+ */
+public void initialize(Node n) {
+
+       Number ret = source.get(n);
+       if(setter.isInteger()) setter.set(n,ret.longValue());
+       else setter.set(n,ret.doubleValue());
+}
+
+//--------------------------------------------------------------------------
+
+}
diff --git a/contrib/psg/src/peersim/vector/VectorComparator.java b/contrib/psg/src/peersim/vector/VectorComparator.java
new file mode 100644 (file)
index 0000000..97f269e
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2006 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.vector;
+
+import java.lang.reflect.*;
+import java.util.*;
+
+import peersim.core.*;
+
+/**
+ * This class provides a generic implementation of the
+ * <code>java.lang.Comparator<code> interface specialized
+ * for {@link Node} objects. Nodes are compared based
+ * on one of their protocols, on which a configurable
+ * method is invoked. Both the protocol id and the
+ * method are specified in the constructor.
+ * <br>
+ * This comparator can be used, for example, to sort
+ * an array of nodes based on method <code>getValue</code>
+ * associated to the protocol <code>pid</code>:
+ * <PRE>
+ * Comparator c = new VectorComparator(pid, "getValue");
+ * Array.sort(Node[] array, c);
+ * </PRE>
+ * Note that differently from other classes in this package,
+ * VectorComparator is declared programmatically in the code
+ * and not in the configuration file. It is included in this
+ * package because it shares the same philosophy of the other
+ * classes.
+ *
+ * @author Alberto Montresor
+ * @version $Revision: 1.1 $
+ */
+public class VectorComparator implements Comparator
+{
+
+//--------------------------------------------------------------------------
+//Fields
+//--------------------------------------------------------------------------
+
+/** Protocol identifier of the protocol to be observed */
+private final int pid;
+
+/** The getter to be used to obtain comparable values */
+private final Method method;
+
+//--------------------------------------------------------------------------
+//Initialization
+//--------------------------------------------------------------------------
+
+public VectorComparator(int pid, String methodName)
+{
+       this.pid = pid;
+       Node n = Network.prototype;
+       if (n == null) {
+               throw new IllegalStateException("No prototype node can be used to search methods");
+       }
+       Object p = n.getProtocol(pid);
+       Class c = p.getClass();
+       try {
+               method = GetterSetterFinder.getGetterMethod(c, methodName);
+       } catch (NoSuchMethodException e) {
+               throw new IllegalArgumentException(e.getMessage());
+       }
+}
+
+
+public int compare(Object o1, Object o2)
+{
+       try {
+       Comparable c1 = (Comparable) method.invoke(((Node) o1).getProtocol(pid));
+       Comparable c2 = (Comparable) method.invoke(((Node) o2).getProtocol(pid));
+       return c1.compareTo(c2);
+       } catch (InvocationTargetException e) {
+               throw new RuntimeException(e.getCause().getMessage());
+       } catch (IllegalAccessException e) {
+               throw new RuntimeException(e.getCause().getMessage());
+       }
+}
+
+}
diff --git a/contrib/psg/src/peersim/vector/VectorObserver.java b/contrib/psg/src/peersim/vector/VectorObserver.java
new file mode 100644 (file)
index 0000000..b971fc2
--- /dev/null
@@ -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.vector;
+
+import peersim.core.*;
+import peersim.util.*;
+
+/**
+ * This class computes and reports statistics information about a vector.
+ * Provided statistics include average, max, min, variance,
+ * etc. Values are printed according to the string format of {@link 
+ * IncrementalStats#toString}.
+ * @see VectControl
+ * @see peersim.vector
+ */
+public class VectorObserver extends VectControl {
+
+
+/** The name of this observer in the configuration */
+private final String prefix;
+
+
+//--------------------------------------------------------------------------
+//Initialization
+//--------------------------------------------------------------------------
+
+/**
+ * Standard constructor that reads the configuration parameters.
+ * Invoked by the simulation engine.
+ * @param prefix the configuration prefix for this class
+ */
+public VectorObserver(String prefix) {
+
+       super(prefix);
+       this.prefix = prefix;
+}
+
+//--------------------------------------------------------------------------
+// Methods
+//--------------------------------------------------------------------------
+
+/**
+ * Prints statistics information about a vector.
+ * Provided statistics include average, max, min, variance,
+ * etc. Values are printed according to the string format of {@link 
+ * IncrementalStats#toString}.
+ * @return always false
+ */
+public boolean execute() {
+
+       IncrementalStats stats = new IncrementalStats();
+
+       for (int j = 0; j < Network.size(); j++)
+       {
+               Number v = getter.get(j);
+               stats.add( v.doubleValue() );
+       }
+       
+       System.out.println(prefix+": "+stats);  
+
+       return false;
+}
+
+}
diff --git a/contrib/psg/src/psgsim/NodeHost.java b/contrib/psg/src/psgsim/NodeHost.java
new file mode 100644 (file)
index 0000000..1dce76f
--- /dev/null
@@ -0,0 +1,74 @@
+package psgsim;
+
+import org.simgrid.msg.Host;
+import peersim.core.Network;
+import peersim.core.Node;
+
+import java.util.Comparator;
+import java.util.Map;
+import java.util.TreeMap;
+
+/**
+ * 
+ * NodeHost class used to make the mapping Node-Host.
+ * 
+ * @author Khaled Baati 26/10/2014
+ * @version version 1.1
+ */
+public class NodeHost {
+
+       /**
+        * A collection of map contained the couple (host,node)
+        */
+       public static TreeMap<Node, Host> mapHostNode = new TreeMap<Node, Host>(
+                       new Comparator<Node>() {
+                               public int compare(Node n1, Node n2) {
+                                       return String.valueOf(n1.getID()).compareTo(
+                                                       String.valueOf(n2.getID()));
+                               }
+                       });
+
+       /**
+        * The main method to make the mapping Node to Host in the
+        * {@link #mapHostNode} field
+        */
+       public static void start() {
+               Host host = null;
+               for (Integer i = 0; i < PSGSimulator.size; i++) {
+                       host = PSGPlatform.hostList[i];
+                       mapHostNode.put(Network.get(i), host);
+               }
+       }
+
+       /**
+        * This static method gets a Node instance associated with a host of your
+        * platform.
+        * 
+        * @param host
+        *            The host associated in your platform.
+        * @return The node associated.
+        */
+       public static Node getNode(Host host) {
+               for (Map.Entry<Node, Host> element : mapHostNode.entrySet()) {
+                       if (element.getValue() == host)
+                               return element.getKey();
+               }
+               return null;
+       }
+
+       /**
+        * This static method gets a host instance associated with the node of your
+        * platform.
+        * 
+        * @param node
+        *            The node associated in your platform.
+        * @return The host associated, else return null (host doesn't exist).
+        */
+       public static Host getHost(Node node) {
+               for (Map.Entry<Node, Host> element : mapHostNode.entrySet()) {
+                       if (element.getKey() == node)
+                               return element.getValue();
+               }
+               return null;
+       }
+}
diff --git a/contrib/psg/src/psgsim/PSGDynamicNetwork.java b/contrib/psg/src/psgsim/PSGDynamicNetwork.java
new file mode 100644 (file)
index 0000000..f4bb3b1
--- /dev/null
@@ -0,0 +1,45 @@
+package psgsim;
+
+import org.simgrid.msg.Host;
+import org.simgrid.msg.HostNotFoundException;
+
+import peersim.core.Node;
+
+/**
+ * 
+ * This class can change the size of networks by adding and removing nodes, as
+ * {@link peersim.dynamics.DynamicNetwork} in peersim.
+ * 
+ * @author Khaled Baati 09/02/2015
+ * @version version 1.1
+ */
+public class PSGDynamicNetwork {
+
+       /**
+        * Removes the node from the network.
+        * 
+        * @param node
+        *            the node to be removed
+        */
+       public static void remove(Node node) {
+               // NodeHost.getHost(node).off();
+               // Host h=NodeHost.mapHostNode.get(node);
+               // NodeHost.mapHostNode.remove(node);
+               PSGSimulator.size = PSGSimulator.size - 1;
+       }
+
+       /**
+        * Adds a node to the network.
+        * 
+        * @param node
+        *            the node to be added
+        * @throws HostNotFoundException 
+        */
+       public static void add(Node node) throws HostNotFoundException {
+               Host host = PSGPlatform.hostList[(int) node.getID()];
+               NodeHost.mapHostNode.put(node, host);
+               if (PSGPlatform.interfED)
+                       new PSGProcessEvent(host, host.getName(), null).start();
+               PSGSimulator.size = PSGSimulator.size + 1;
+       }
+}
diff --git a/contrib/psg/src/psgsim/PSGPlatform.java b/contrib/psg/src/psgsim/PSGPlatform.java
new file mode 100644 (file)
index 0000000..90c7c87
--- /dev/null
@@ -0,0 +1,329 @@
+package psgsim;
+
+import java.io.*;
+import java.util.Comparator;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.TreeMap;
+
+import org.jdom2.*;
+import org.jdom2.output.*;
+import org.simgrid.msg.Host;
+import org.simgrid.msg.Msg;
+
+import peersim.config.Configuration;
+import peersim.core.Control;
+import peersim.core.Protocol;
+
+/**
+ * A class store different configuration information for simulation. It creates
+ * the deployment file according to this informations.
+ * 
+ * @author Khaled Baati 26/10/2014
+ * @version version 1.1
+ */
+
+public class PSGPlatform {
+
+       enum timeUnit {
+               us, ms, sec;
+       }
+
+       /** unit of measure. **/
+       static int unit;
+
+       /** the clock. **/
+       static double time;
+
+       /** the default unit of measure **/
+       static final String sec = "sec";
+
+       /** All protocols defined in the configuration file. **/
+       static Protocol[] protocolsName;
+
+       /** A numeric identifier associated for each protocol. **/
+       static int[] pid;
+
+       /** List of hos.t **/
+       static Host[] hostList;
+
+       /** A collection map represents the Control and its associated step. **/
+       static Map<Control, Double> controlStepMap = new LinkedHashMap<Control, Double>();
+
+       /** A collection map represents the protocol and its associated pid. **/
+       static TreeMap<Protocol, Integer> protocolsPidsMap = new TreeMap<Protocol, Integer>(
+                       new Comparator<Protocol>() {
+                               public int compare(Protocol p1, Protocol p2) {
+                                       return p1.toString().compareTo(p2.toString());
+                               }
+                       });
+
+       /** A collection map represents all CDProtocol and its associated step **/
+       static TreeMap<Protocol, Double> cdProtocolsStepMap = new TreeMap<Protocol, Double>(
+                       new Comparator<Protocol>() {
+                               public int compare(Protocol p1, Protocol p2) {
+                                       return p1.toString().compareTo(p2.toString());
+                               }
+                       });
+       /** the default platform file **/
+       static final String platformFile = "platforms/psg.xml";
+
+       /** the deployment file **/
+       static final String deploymentFile = "deployment.xml";
+
+       static Element racine;
+       static Document document;
+       static boolean interfED = false;
+       static boolean interfCD = false;
+
+       /** Prepare the deployment file **/
+       static {
+               DocType dtype = new DocType("platform",
+                               "http://simgrid.gforge.inria.fr/simgrid.dtd");
+               racine = new Element("platform");
+               document = new Document(racine, dtype);
+               Attribute version = new Attribute("version", "3");
+               racine.setAttribute(version);
+       }
+
+       // ========================== methods ==================================
+       // =====================================================================
+
+       /**
+        * Convert PS unit time to Simgrid unit time
+        * 
+        * @param valeur
+        *            the value to convert
+        * @return time converted
+        */
+       public static double psToSgTime(long valeur) {
+               timeUnit unit = unit();
+               switch (unit) {
+               case us:
+                       return ((double) valeur) / 1000000;
+               case ms:
+                       return ((double) valeur) / 1000;
+               default:
+                       return (double) valeur;
+
+               }
+       }
+
+       /**
+        * Convert Simgrid unit time to PS unit time
+        * 
+        * @param valeur
+        *            the value to convert
+        * @return time converted
+        */
+       public static long sgToPsTime(double valeur) {
+               timeUnit unit = unit();
+               switch (unit) {
+               case us:
+                       return (long) valeur * 1000000;
+               case ms:
+                       return (long) valeur * 1000;
+               default:
+                       return (long) valeur;
+
+               }
+       }
+
+       /**
+        * 
+        * @return the duration of simulation.
+        */
+       public static long getDuration() {
+               return Configuration.getLong("simulation.duration");
+       }
+
+       /**
+        * 
+        * @return PeerSim Time
+        */
+       public static long getTime() {
+               return sgToPsTime(Msg.getClock());
+       }
+
+       /**
+        * 
+        * @return the Simgrid Clock
+        */
+       public static double getClock() {
+               return Msg.getClock();
+       }
+
+       /**
+        * Load and run initializers.
+        */
+       public static void init() {
+               Object[] inits = Configuration.getInstanceArray("init");
+               String names[] = Configuration.getNames("init");
+               for (int i = 0; i < inits.length; ++i) {
+                       System.err.println("- Running initializer " + names[i] + ": "
+                                       + inits[i].getClass().toString());
+                       ((Control) inits[i]).execute();
+               }
+       }
+
+       /**
+        * Load all controls and stores them in {@link #controlStepMap} collection
+        * to be scheduled, and executed in {@link psgsim.PSGProcessController}.
+        */
+       public static void control() {
+               // load controls
+               String[] names = Configuration.getNames("control");
+               Control control;
+               for (int i = 0; i < names.length; ++i) {
+                       control = (Control) Configuration.getInstance(names[i]);
+                       Long stepControl = Configuration.getLong(names[i] + "." + "step");
+                       controlStepMap.put(control, psToSgTime(stepControl));
+               }
+       }
+
+       /**
+        * Lookup all protocols in the configuration file
+        */
+       public static void protocols() {
+               String[] names = Configuration.getNames("protocol");
+               Class[] interfaces;
+               protocolsName = new Protocol[names.length];
+               pid = new int[names.length];
+               boolean save = false;
+               for (int i = 0; i < names.length; i++) {
+                       protocolsName[i] = (Protocol) Configuration.getInstance(names[i]);
+                       if (i == names.length - 1)
+                               save = true;
+                       userProtocol(protocolsName[i], names[i], save);
+                       pid[i] = i;
+                       protocolsPidsMap.put(protocolsName[i], pid[i]);
+               }
+
+       }
+
+       /**
+        * Lookup CDProtocol and EDProtocol among all protocols
+        * 
+        * @param prot
+        *            the protocol class
+        * @param names
+        *            the protocol name
+        * @param save
+        *            parameter equal true when parsing all protocols
+        */
+       public static void userProtocol(Protocol prot, String names, boolean save) {
+               Class[] interfaces = prot.getClass().getInterfaces();
+               for (int j = 0; j < interfaces.length; j++) {
+                       if (interfaces[j].getName().endsWith("EDProtocol")) {
+                               interfED = true;
+                       }
+                       if (interfaces[j].getName().endsWith("CDProtocol")) {
+                               String protName = names.substring("protocol".length() + 1);
+                               long step = Configuration.getLong("protocol" + "." + protName
+                                               + "." + "step");
+                               cdProtocolsStepMap.put(prot, psToSgTime(step));
+                       }
+               }
+               if (save) {
+                       edProt();
+               }
+       }
+
+       /**
+        * 
+        */
+       private static void edProt() {
+               Host hostVal;
+               hostList = Host.all();
+               for (int i = 0; i < PSGSimulator.size; i++) {
+                       hostVal = hostList[i];
+                       Element process = new Element("process");
+                       racine.addContent(process);
+                       Attribute host = new Attribute("host", hostVal.getName());
+                       Attribute function = new Attribute("function",
+                                       "psgsim.PSGProcessEvent");
+                       process.setAttribute(host);
+                       process.setAttribute(function);
+               }
+               save(deploymentFile);
+
+       }
+
+       /**
+        * 
+        */
+       @Deprecated
+       private static void cdProt() {
+               for (int i = 0; i < PSGSimulator.size; i++) {
+                       Element process = new Element("process");
+                       racine.addContent(process);
+                       Attribute host = new Attribute("host", String.valueOf(i));
+                       Attribute function = new Attribute("function",
+                                       "psgsim.PSGProcessCycle");
+                       process.setAttribute(host);
+                       process.setAttribute(function);
+
+               }
+               save("deployment.xml");
+
+       }
+
+       /**
+        * Reads given configuration property: "platform". If not found, returns the
+        * default value.
+        * 
+        * @return the platform file
+        */
+       public static String platformFile() {
+               String defFile = platformFile;
+               String file = Configuration.getString("platform", defFile);
+               return file;
+       }
+
+       /**
+        * Reads given configuration property: "unit". If not found, returns the
+        * default value (ms).
+        * 
+        * @return the unit of measure
+        */
+       public static timeUnit unit() {
+               String defUnit = sec;
+               String unit = Configuration.getString("unit", defUnit);
+               timeUnit t = timeUnit.valueOf(unit);
+               return t;
+       }
+
+       /**
+        * Create the deployment file
+        * 
+        * @param file
+        *            the name of the deployment file
+        */
+       public static void save(String file) {
+               try {
+                       // On utilise ici un affichage classique avec getPrettyFormat()
+                       XMLOutputter out = new XMLOutputter(Format.getPrettyFormat());
+                       out.output(document, new FileOutputStream(file));
+               } catch (java.io.IOException e) {
+               }
+       }
+
+       /**
+        * Delete the deployment file
+        * 
+        * @param path
+        *            the path of the deployment file
+        */
+       public static void delete(String path) {
+               File file = new File(path);
+               try {
+                       file.delete();
+               } catch (Exception e) {
+                       System.err.println("deployment file not found");
+
+               }
+               System.err.println(path + "file deleted");
+
+       }
+
+}
diff --git a/contrib/psg/src/psgsim/PSGProcessController.java b/contrib/psg/src/psgsim/PSGProcessController.java
new file mode 100644 (file)
index 0000000..d587691
--- /dev/null
@@ -0,0 +1,68 @@
+package psgsim;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+import org.simgrid.msg.Host;
+import org.simgrid.msg.MsgException;
+
+import peersim.core.Control;
+
+/**
+ * This class executes all controls object scheduled in the
+ * {@link PSGPlatform#controlStepMap} collection.
+ * 
+ * @author Khaled Baati 10/12/2014
+ * @version version 1.1
+ */
+public class PSGProcessController extends org.simgrid.msg.Process {
+       
+       private Map<Control, Double> controlStepMapTmp = new LinkedHashMap<Control, Double>();
+
+       public PSGProcessController(Host host, String name, String[] args) {
+               super(host, name, null);
+       }
+
+       @Override
+       public void main(String[] args) throws MsgException {
+               Double nextControlEvent;
+               for (Map.Entry<Control, Double> entry : PSGPlatform.controlStepMap
+                               .entrySet()) {
+                       controlStepMapTmp.put(entry.getKey(), entry.getValue());
+               }
+               while (PSGPlatform.getTime() <= PSGPlatform.getDuration()) {
+                       for (Map.Entry<Control, Double> entrytmp : controlStepMapTmp
+                                       .entrySet()) {
+                               Control cle = entrytmp.getKey();
+                               Double valeur = entrytmp.getValue();
+                               if (PSGPlatform.getTime() % valeur == 0) {
+                                       cle.execute();
+                                       if (PSGPlatform.getTime() != 0)
+                                               for (Map.Entry<Control, Double> entry : PSGPlatform.controlStepMap
+                                                               .entrySet()) {
+                                                       if (cle == entry.getKey())
+                                                               controlStepMapTmp.replace(cle, valeur, valeur
+                                                                               + entry.getValue());
+
+                                               }
+                               }
+                       }
+                       nextControlEvent = next();
+                       if (nextControlEvent + PSGPlatform.getTime() >= PSGPlatform.getDuration()) {
+                               break;
+                       } else {
+                               waitFor(nextControlEvent);
+                       }
+               }
+       }
+
+       private Double next() {
+               Double min = controlStepMapTmp.values().iterator().next();
+               for (Map.Entry<Control, Double> entry : controlStepMapTmp.entrySet()) {
+                       Double valeur = (entry.getValue() - PSGPlatform.getClock());
+                       if (min > valeur)
+                               min = valeur;
+               }
+
+               return min;
+       }
+}
\ No newline at end of file
diff --git a/contrib/psg/src/psgsim/PSGProcessCycle.java b/contrib/psg/src/psgsim/PSGProcessCycle.java
new file mode 100644 (file)
index 0000000..e0931b1
--- /dev/null
@@ -0,0 +1,59 @@
+package psgsim;
+
+import java.util.Map.Entry;
+
+import org.simgrid.msg.Host;
+import peersim.cdsim.CDProtocol;
+import peersim.core.Node;
+import peersim.core.Protocol;
+
+/**
+ * This class handle an event of type NextCycleEvent, received on the protocol
+ * identified by a pid among all CDProtocols defined in the
+ * {@link PSGPlatform#cdProtocolsStepMap} collection.
+ * <p>
+ * It executes the nextCyle method associated to this protocol.
+ * 
+ * @author Khaled Baati 27/10/2014
+ * @version version 1.1
+ */
+public class PSGProcessCycle {
+
+       /**
+        * Executes the nextCycle method of the CDprotocol with the appropriate
+        * parameters, and schedules the next call using {@link PSGSimulator#add}.
+        * 
+        * @param host
+        *            the host on which this component is run
+        * @param name
+        *            the host's name
+        * @param delay
+        *            the start time
+        * @param event
+        *            the actual event
+        * @param pid
+        *            the protocol identifier
+        */
+       public static void nextCycle(Host host, String name, double delay,
+                       Object event, int pid) {
+               CDProtocol cdp = null;
+               Node node = NodeHost.getNode(host);
+               cdp = (CDProtocol) node.getProtocol(pid);
+               cdp.nextCycle(node, pid);
+               PSGTransport.flush();
+               for (Entry<Protocol, Double> entry : PSGPlatform.cdProtocolsStepMap
+                               .entrySet()) {
+                       Double step = entry.getValue();
+                       for (Entry<Protocol, Integer> p : PSGPlatform.protocolsPidsMap
+                                       .entrySet()) {
+                               if (p.getValue() == pid) {
+                                       break;
+                               }
+                       }
+                       if (PSGPlatform.getTime() <= PSGPlatform.getDuration() && host.isOn()) {
+                               PSGSimulator.add(PSGPlatform.sgToPsTime(step), event, node, pid);
+                       }
+               }
+       }
+
+}
diff --git a/contrib/psg/src/psgsim/PSGProcessEvent.java b/contrib/psg/src/psgsim/PSGProcessEvent.java
new file mode 100644 (file)
index 0000000..cc4f73c
--- /dev/null
@@ -0,0 +1,62 @@
+package psgsim;
+
+import org.simgrid.msg.Host;
+import org.simgrid.msg.MsgException;
+
+import peersim.core.Node;
+import peersim.edsim.EDProtocol;
+
+/**
+ * This class extends {@link org.simgrid.msg.Process} which creates a process
+ * for each host (corresponding to node in peersim) in the system.
+ * <p>
+ * The main method of this class is to handle events received, by calling the
+ * processEvent method on the corresponding node and pid.
+ * <p>
+ * See {@link peersim.edsim.EDProtocol#processEvent}
+ * 
+ * @author Khaled Baati 28/10/2014
+ * @version version 1.1
+ */
+public class PSGProcessEvent extends org.simgrid.msg.Process {
+       /** The delivered event **/
+       private PSGTask task;
+       /** The current protocol **/
+       private EDProtocol prot;
+       /** The identifier of the current protocol **/
+       private int pid;
+
+       /**
+        * Constructs a new process from the name of a host.
+        * 
+        * @param host
+        *            the local host to create according to the active node in
+        *            peersim
+        * @param name
+        *            the host's name
+        * @param args
+        *            The arguments of main method of the process.
+        */
+       public PSGProcessEvent(Host host, String name, String[] args) {
+               super(host, name, args);
+       }
+
+       @Override
+       public void main(String[] args) throws MsgException {
+               Node node = NodeHost.getNode(getHost());
+               Host.setAsyncMailbox(getHost().getName());
+               while (PSGPlatform.getTime() < PSGPlatform.getDuration()) {
+                       task = null;
+                       task = (PSGTask) PSGTask.receive(Host.currentHost().getName(),
+                                       PSGPlatform.psToSgTime(PSGPlatform.getDuration() - PSGPlatform.getTime()-1));
+                       if (task != null && PSGPlatform.getTime() < PSGPlatform.getDuration()) {
+                               pid = task.getPid();
+                               prot = (EDProtocol) node.getProtocol(pid);
+                               prot.processEvent(node, pid, task.getEvent());
+                               PSGTransport.flush();
+                       } else
+                               break;
+               }
+       }
+
+}
diff --git a/contrib/psg/src/psgsim/PSGProcessLauncher.java b/contrib/psg/src/psgsim/PSGProcessLauncher.java
new file mode 100644 (file)
index 0000000..97d89c0
--- /dev/null
@@ -0,0 +1,74 @@
+package psgsim;
+
+import org.simgrid.msg.Host;
+import org.simgrid.msg.MsgException;
+
+import peersim.core.Node;
+import peersim.edsim.EDProtocol;
+import peersim.edsim.NextCycleEvent;
+
+/**
+ * This class extends {@link org.simgrid.msg.Process}, it creates a process for
+ * each event added in {@link PSGSimulator#add}.
+ * <p>
+ * This class performs to launch the appropriate call according to the type of
+ * the event;
+ * <p>
+ * - A NextCycleEvent: the event will be delivered to the
+ * {@link PSGProcessCycle} for treatment.
+ * <p>
+ * - Otherwise the event is delivered to the destination protocol, that must
+ * implement {@link EDProtocol}, and the processEvent method is executed.
+ * 
+ * @author Khaled Baati 12/11/2014
+ * @version version 1.1
+ */
+public class PSGProcessLauncher extends org.simgrid.msg.Process {
+       private EDProtocol prot = null;
+       private int pid;
+       private double delay;
+       private Object event;
+       private Host host;
+
+       /**
+        * Constructs a new process from the name of a host and with the associated
+        * parameters
+        * 
+        * @param host
+        *            the local host
+        * @param name
+        *            the host's name
+        * @param delay
+        *            the start time of the process
+        * @param event
+        *            the event added to the simulator
+        * @param pid
+        *            the protocol identifier
+        */
+       public PSGProcessLauncher(Host host, String name, double delay, Object event,
+                       int pid) {
+               super(host, name, null, delay, -1);
+               this.host = host;
+               this.pid = pid;
+               this.event = event;
+               this.delay = delay;
+       }
+
+       public PSGProcessLauncher(Host host, String name, String[] args) {
+
+       }
+
+       @Override
+       public void main(String[] args) throws MsgException {
+               Node node = NodeHost.getNode(host);
+               if (event instanceof NextCycleEvent) {
+                       PSGProcessCycle.nextCycle(Host.currentHost(), host.getName(),
+                                       delay, event, pid);
+               } else {
+                       prot = (EDProtocol) node.getProtocol(pid);
+                       prot.processEvent(node, pid, event);
+                       PSGTransport.flush();
+               }
+               waitFor(500);
+       }
+}
\ No newline at end of file
diff --git a/contrib/psg/src/psgsim/PSGSimulator.java b/contrib/psg/src/psgsim/PSGSimulator.java
new file mode 100644 (file)
index 0000000..4d45d4e
--- /dev/null
@@ -0,0 +1,98 @@
+package psgsim;
+
+import org.simgrid.msg.Host;
+import org.simgrid.msg.HostNotFoundException;
+import org.simgrid.msg.Msg;
+import org.simgrid.msg.NativeException;
+
+import peersim.core.CommonState;
+import peersim.core.Network;
+import peersim.core.Node;
+
+/**
+ * This is the main entry point to Simgrid simulator. This class loads the
+ * different parameters and initializes the simulation.
+ * 
+ * @author Khaled Baati 14/10/2014
+ * @version version 1.1
+ */
+public class PSGSimulator {
+       public static int size;
+
+       static {
+               Network.reset();
+               size = Network.size();
+       }
+
+       // ========================== methods ==================================
+       // =====================================================================
+
+       /**
+        * Adds a new event to be scheduled, specifying the number of time units of
+        * delay (in seconds), the node and the protocol identifier to which the
+        * event will be delivered. A {@link psgsim.PSGProcessLauncher} process will
+        * be created according to this event.
+        * 
+        * @param delay
+        *            The number of time units (seconds in simgrid) before the event
+        *            is scheduled.
+        * @param event
+        *            The object associated to this event
+        * @param src
+        *            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 src, int pid) {
+               Host host = NodeHost.getHost(src);
+               double startTime = PSGPlatform.psToSgTime(delay) + Msg.getClock(); 
+               if (startTime < PSGPlatform.psToSgTime(PSGPlatform.getDuration()) ) {
+                       try {
+                               /**
+                                * random instruction associated to Heap.add(...) method in
+                                * peersim.edsim
+                                **/
+                               CommonState.r.nextInt(1 << 8);
+                               new PSGProcessLauncher(host, host.getName(), startTime, event,
+                                               pid).start();
+                       } catch (HostNotFoundException e) {
+                               System.err.println("Host not found");
+                       }
+               }
+
+       }
+
+       // ========================== main method ==================================
+       // =====================================================================
+       public static void main() throws NativeException, HostNotFoundException {
+
+               String platformfile = PSGPlatform.platformFile();
+               System.err.println(platformfile + " loaded");
+               String[] arguments = { platformfile, "deployment.xml" };
+               Msg.init(arguments);
+
+               /** construct the platform */
+               Msg.createEnvironment(arguments[0]);
+
+               PSGPlatform.protocols();
+
+               /** deploy the application **/
+               Msg.deployApplication(arguments[1]);
+
+               /** construct the host-node mapping **/
+               NodeHost.start();
+
+               /** Process Controller **/
+               PSGPlatform.control();
+               new PSGProcessController(PSGPlatform.hostList[0],
+                               PSGPlatform.hostList[0].getName(), null).start();
+
+               /** Load and execute the initializers classes in the configuration file **/
+               PSGPlatform.init();
+
+               PSGPlatform.delete("deployment.xml");
+               /** execute the simulation. **/
+               Msg.run();
+       }
+}
diff --git a/contrib/psg/src/psgsim/PSGTask.java b/contrib/psg/src/psgsim/PSGTask.java
new file mode 100644 (file)
index 0000000..6d25e2c
--- /dev/null
@@ -0,0 +1,85 @@
+package psgsim;
+
+import org.simgrid.msg.HostFailureException;
+import org.simgrid.msg.Task;
+import org.simgrid.msg.TimeoutException;
+import org.simgrid.msg.TransferFailureException;
+
+/**
+ * The PSGTask includes all the parameters of sending a message as the size, the
+ * compute duration and the protocol identifier.
+ * 
+ * @author Khaled Baati 28/10/2014
+ * @version version 1.1
+ */
+public class PSGTask extends org.simgrid.msg.Task {
+       /** The Message to be sent **/
+       private Object event;
+       /** The protocol identifier **/
+       private int pid;
+
+       /**
+        * Construct a new task to be sent.
+        * 
+        * @param name
+        *            The name of task
+        * @param computeDuration
+        *            The compute duration
+        * 
+        * @param messageSize
+        *            The size of the message
+        * @param event
+        *            The message to be sent
+        * @param pid
+        *            The protocol identifier
+        */
+       public PSGTask(String name, double computeDuration, double messageSize,
+                       Object event, int pid) {
+               super(name, computeDuration, messageSize);
+               this.event = event;
+               this.pid = pid;
+       }
+
+       /**
+        * 
+        * @return the protocol identifier
+        */
+       public int getPid() {
+               return pid;
+       }
+
+       /**
+        * 
+        * @return the message
+        */
+       public Object getEvent() {
+               return event;
+       }
+
+       /**
+        * Retrieves next task on the mailbox identified by the specified name (wait
+        * at most timeout seconds)
+        * 
+        * @param mailbox
+        *            the mailbox on where to receive the task
+        * @param timeout
+        *            the timeout to wait for receiving the task
+        * @return the task
+        */
+       public static Task receive(String mailbox, double timeout) {
+               double time = PSGPlatform.getClock();
+               if (time + timeout > PSGPlatform.getClock()) {
+                       try {
+                               return receive(mailbox, timeout, null);
+                       } catch (TimeoutException e) {
+                       } catch (TransferFailureException e) {
+                               e.printStackTrace();
+                       } catch (HostFailureException e) {
+                               e.printStackTrace();
+                       }
+               }
+               return null;
+
+       }
+
+}
diff --git a/contrib/psg/src/psgsim/PSGTransport.java b/contrib/psg/src/psgsim/PSGTransport.java
new file mode 100644 (file)
index 0000000..db964b4
--- /dev/null
@@ -0,0 +1,115 @@
+package psgsim;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+import peersim.config.Configuration;
+import peersim.config.IllegalParameterException;
+import peersim.core.CommonState;
+import peersim.core.Node;
+import peersim.transport.Transport;
+
+/**
+ * PSGTransport is the transport layer. it is responsible for sending messages.
+ * 
+ * @author Khaled Baati 28/10/2014
+ * @version 1.1
+ */
+public class PSGTransport implements Transport {
+
+       private static double computeDuration = 0;
+       private PSGTask task;
+       private static Map<PSGTask, String> taskToSend = new LinkedHashMap<PSGTask, String>();
+
+       /**
+        * String name of the parameter used to configure the minimum latency. * @config
+        */
+       private static final String PAR_MINDELAY = "mindelay";
+
+       /**
+        * String name of the parameter used to configure the maximum latency.
+        * Defaults to {@value #PAR_MINDELAY}, which results in a constant delay.
+        * 
+        * @config
+        */
+       private static final String PAR_MAXDELAY = "maxdelay";
+
+       /** Minimum delay for message sending */
+       private long min;
+       /** Maximum delay for message sending */
+       private long max;
+
+       /**
+        * Difference between the max and min delay plus one. That is, max delay is
+        * min+range-1.
+        */
+       private long range;
+
+       public PSGTransport() {
+
+       }
+
+       public PSGTransport(String prefix) {
+               min = Configuration.getLong(prefix + "." + PAR_MINDELAY);
+               max = Configuration.getLong(prefix + "." + PAR_MAXDELAY, min);
+               if (max < min)
+                       throw new IllegalParameterException(prefix + "." + PAR_MAXDELAY,
+                                       "The maximum latency cannot be smaller than the minimum latency");
+               range = max - min + 1;
+       }
+
+       /**
+        * Returns <code>this</code>. This way only one instance exists in the
+        * system that is linked from all the nodes. This is because this protocol
+        * has no node specific state.
+        */
+       public Object clone() {
+               return this;
+       }
+
+       @Override
+       public void send(Node src, Node dest, Object msg, int pid) {
+               double commSizeLat = 0;
+               /**
+                * random instruction associated to UniformRandomTransport.send(...)
+                * method in peersim.transport
+                **/
+               long delay = (range == 1 ? min : min + CommonState.r.nextLong(range));
+               CommonState.r.nextInt(1 << 8);
+               if (msg instanceof Sizable) {
+                       commSizeLat = ((Sizable) msg).getSize();
+               }
+
+               task = new PSGTask("task sender_" + src.getID(), computeDuration,
+                               commSizeLat, msg, pid);
+               taskToSend.put(this.task, NodeHost.getHost(dest).getName());
+
+       }
+
+       /**
+        * Process for sending all messages in the queue.
+        */
+       public static void flush() {
+               Map<PSGTask, String> taskToSendCopy = new LinkedHashMap<PSGTask, String>();
+               for (Map.Entry<PSGTask, String> entry : taskToSend.entrySet()) {
+                       taskToSendCopy.put(entry.getKey(), entry.getValue());
+               }
+               taskToSend.clear();
+               for (Map.Entry<PSGTask, String> entry : taskToSendCopy.entrySet()) {
+                       PSGTask task = entry.getKey();
+                       String dest = entry.getValue();
+                       task.dsend(dest);
+               }
+               taskToSendCopy.clear();
+
+       }
+
+       @Override
+       public long getLatency(Node src, Node dest) {
+               /**
+                * random instruction associated to
+                * UniformRandomTransport.getLatency(...) method in peersim.transport
+                **/
+               return (range == 1 ? min : min + CommonState.r.nextLong(range));
+       }
+}
diff --git a/contrib/psg/src/psgsim/Sizable.java b/contrib/psg/src/psgsim/Sizable.java
new file mode 100644 (file)
index 0000000..16196f6
--- /dev/null
@@ -0,0 +1,18 @@
+package psgsim;
+
+/**
+ * An interface which defines a size for the message or the event to be sent. If you
+ * wish that your message has a size, your class message must implements this
+ * interface and defines a size parameter in the constructor.
+ * 
+ * @author Khaled Baati 05/02/2015
+ * @version 1.1
+ * 
+ */
+public interface Sizable {
+       /**
+        * 
+        * @return The size of the message
+        */
+       public double getSize();
+}
diff --git a/contrib/psg/test.sh b/contrib/psg/test.sh
new file mode 100755 (executable)
index 0000000..f5b7f09
--- /dev/null
@@ -0,0 +1,45 @@
+#!/bin/bash
+
+if [ $(uname -m) = "i686" ]; then
+       eval ulimit -s 64
+else 
+       eval ulimit -s 128
+fi
+
+echo -e "\n";
+echo '------------- Execute the edaggregation example under PSG -------------';
+echo -e "\n";
+java -Xmx1024m -cp lib.jar:classes peersim.Simulator configs/edaggregationPSG.txt
+echo -e "\n";
+echo '------------- Execute the edaggregation example under PS -------------';
+echo -e "\n";
+java -Xmx1024m -cp lib.jar:classes peersim.Simulator configs/edaggregation.txt
+echo -e "\n";
+echo '------------- Execute the chord example under PSG -------------';
+echo -e "\n";
+java -Xmx1024m -cp lib.jar:classes peersim.Simulator configs/chordPSG.txt
+echo -e "\n";
+echo '------------- Execute the chord example under PS -------------';
+echo -e "\n";
+java -Xmx1024m -cp lib.jar:classes peersim.Simulator configs/chord.txt
+echo -e "\n";
+echo '------------- Compare the 2 results PS and PSG -------------';
+echo -e "\n";
+
+cd outputs
+
+ListeRep="$(find * -type d -prune)"   # liste des repertoires
+for Rep in ${ListeRep}; do     
+       cd $Rep
+       VAR=$(diff ps.txt psg.txt)
+       if [ "${VAR}"1 = 1 ]
+               then
+                echo The results of diff "for" the $Rep example is '.............:)';
+       else
+                echo The results of diff "for" the $Rep example is '.............:(';
+       fi
+       cd ..
+done
+echo -e "\n";
+exit 0
+
diff --git a/contrib/psg/tutorial.pdf b/contrib/psg/tutorial.pdf
new file mode 100644 (file)
index 0000000..591649f
Binary files /dev/null and b/contrib/psg/tutorial.pdf differ
index 0851aff..3db49d5 100644 (file)
@@ -1,4 +1,4 @@
-/*! @page introduction Introduction to SimGrid 
+/*! @page introduction Introduction to SimGrid
 
 [SimGrid](http://simgrid.gforge.inria.fr/) is a toolkit
 that provides core functionalities for the simulation of distributed
@@ -9,7 +9,7 @@ distributed and parallel application scheduling on distributed computing
 platforms ranging from simple network of workstations to Computational
 Grids.
 
-# Scenario 
+# Scenario
 The goal of this practical session is to illustrate various usage of
 the MSG interface. To this end we will use the following simple setting:
 
@@ -28,25 +28,25 @@ interesting questions:
     The most obvious algorithm would be to send tasks to workers in a
     round-robin fashion. This is the initial code we provide you.
 
-    A less obvious one but probably more efficient would be to set up
-    a request mechanism where client first ask for tasks, which allows
+    A less obvious but probably more efficient approach would be to set up
+    a request mechanism where client first ask for tasks, which allows
     the server to decide which request to answer and possibly to send
     the tasks to the fastest machines. Maybe you can think of a
     smarter mechanism...
 
-- How much tasks should the client ask for?
-    
-    Indeed, if we set up a request mechanism and that workers only
+- How many tasks should the client ask for?
+
+    Indeed, if we set up a request mechanism so that workers only
     send request whenever they have no more task to process, they are
     likely to be poorly exploited since they will have to wait for the
     master to consider their request and for the input data to be
     transferred. A client should thus probably request a pool of tasks
-    but if it requests too much task, it is likely to lead to a poor
+    but if it requests too many tasks, it is likely to lead to a poor
     load-balancing...
-    
+
 - How is the quality of such algorithm dependent on the platform
-    characteristics? on the task characteristics?
-    
+    characteristics and on the task characteristics?
+
     Whenever the input communication time is very small compared to
     processing time and workers are homogeneous, it is likely that the
     round-robin algorithm performs very well. Would it still hold true
@@ -54,20 +54,20 @@ interesting questions:
     a volunteer computing system ?
 
 - The network topology interconnecting the master and the workers
-  may be quite complicated. How does such topology impact the
+  may be quite complicated. How does such topology impact the
   previous result?
 
     When data transfers are the bottleneck, it is likely that a good
-    modeling of the platform becomes essential, in which case, you may
+    modeling of the platform becomes essential. In this case, you may
     want to be able to account for complex platform topologies.
 
 - Do the algorithms depend on a perfect knowledge of this
   topology?
 
     Should we still use a flat master worker deployment or should we
-    use a 
+    use a
 
-- How is such algorithm sensitive to external workload variation?
+- How is such an algorithm sensitive to external workload variation?
 
     What if bandwidth, latency and power can vary with no warning?
     Shouldn't you study whether your algorithm is sensitive to such
@@ -76,13 +76,13 @@ interesting questions:
 - Although an algorithm may be more efficient than another, how
   does it interfere with other applications?
 
-    As you can see, this very simple setting may need to evolve way
-    beyond what you initially imagined. 
+    %As you can see, this very simple setting may need to evolve way
+    beyond what you initially imagined.
 
     <blockquote> Premature optimization is  the root of all evil. -- D.E.Knuth</blockquote>
 
-    Furthermore, writing your own simulator is much harder that what you
-    may imagine. This is why should rely on an established and flexible
+    Furthermore, writing your own simulator is much harder than you
+    may imagine. This is why you should rely on an established and flexible
     one.
 
 The following figure is a screenshot of [triva][fn:1] visualizing a [SimGrid
@@ -97,7 +97,7 @@ usage over a long period of time.
 ## Tutorials
 
 A lot of information on how to install and use Simgrid are
-available on the [online documentation][fn:4] and in the tutorials:
+provided by the [online documentation][fn:4] and by several tutorials:
 
 - http://simgrid.gforge.inria.fr/tutorials/simgrid-use-101.pdf
 - http://simgrid.gforge.inria.fr/tutorials/simgrid-tracing-101.pdf
@@ -105,15 +105,24 @@ available on the [online documentation][fn:4] and in the tutorials:
 
 ## Installing SimGrid
 
+In case you're using [Debian](https://www.debian.org) or a derivate,
+such as Ubuntu or Mint, you can install SimGrid by using the provided
+packages:
+
     sudo apt-get install libsimgrid-dev
 
 This tutorial requires simgrid 3.8 at least so you may need to get
 the [debian packages](http://packages.debian.org/libsimgrid-dev).
 
+Please note that your distribution may ship with an old version of
+SimGrid; you may want to use [a newer release](https://gforge.inria.fr/frs/?group_id=12)
+or even [clone our git repository](https://gforge.inria.fr/frs/?group_id=12)
+(a [GitHub mirror](https://github.com/mquinson/simgrid) is also available).
+
 # Recommended Steps
 
-## Installing Viva 
-   
+## Installing Viva
+
 This [software][fn:1] will be useful to make fancy graph or treemap
 visualizations and get a better understanding of simulations. You
 will first need to install pajeng:
@@ -121,7 +130,7 @@ will first need to install pajeng:
 ~~~~{.sh}
 sudo apt-get install git cmake build-essential libqt4-dev  libboost-dev freeglut3-dev ;
 git clone https://github.com/schnorr/pajeng.git
-cd pajeng && mkdir -p build &&  cd build && cmake ../ -DCMAKE_INSTALL_PREFIX=$HOME &&  make -j install 
+cd pajeng && mkdir -p build &&  cd build && cmake ../ -DCMAKE_INSTALL_PREFIX=$HOME &&  make -j install
 cd ../../
 ~~~~
 
@@ -130,11 +139,11 @@ Then you can install viva.
 ~~~~{.sh}
 sudo apt-get install libboost-dev libconfig++-dev libconfig8-dev libgtk2.0-dev freeglut3-dev
 git clone https://github.com/schnorr/viva.git
-cd viva && mkdir -p build_graph &&  cd build_graph && cmake ../ -DTUPI_LIBRARY=ON -DVIVA=ON -DCMAKE_INSTALL_PREFIX=$HOME &&  make -j install 
+cd viva && mkdir -p build_graph &&  cd build_graph && cmake ../ -DTUPI_LIBRARY=ON -DVIVA=ON -DCMAKE_INSTALL_PREFIX=$HOME &&  make -j install
 cd ../../
 ~~~~
 
-## Installing Paje 
+## Installing Paje
 
 This [software][fn:5] provides a Gantt-chart visualization.
 
@@ -142,7 +151,7 @@ This [software][fn:5] provides a Gantt-chart visualization.
 sudo apt-get install paje.app
 ~~~~
 
-## Installing Vite 
+## Installing Vite
 
 This software provides a [Gantt-chart visualization][fn:6].
 
@@ -152,7 +161,7 @@ sudo apt-get install vite
 
 # Let's get Started
 ## Setting up and Compiling
-   
+
 The corresponding archive with all source files and platform files
 can be obtained [here](http://simgrid.gforge.inria.fr/tutorials/msg-tuto/msg-tuto.tgz).
 
@@ -162,7 +171,7 @@ cd msg-tuto/src
 make
 ~~~~
 
-As you can see, there is already a nice Makefile that compiles
+%As you can see, there is already a nice Makefile that compiles
 everything for you. Now the tiny example has been compiled and it
 can be easily run as follows:
 
@@ -191,7 +200,7 @@ For a really fancy output, you should use [viva/triva][fn:1]:
     --cfg=tracing/uncategorized:yes --cfg=viva/uncategorized:uncat.plist
 LANG=C ; viva simgrid.trace uncat.plist
 ~~~~
+
 For a more classical Gantt-Chart visualization, you can produce a
 [Paje][fn:5] trace:
 
@@ -258,23 +267,23 @@ new deployment file `deployment1.xml` should thus now simply be:
 </platform>
 ~~~~
 
-To this end you may need the following MSG functions, whose
-behavior is described in the [online documentation](http://simgrid.gforge.inria.fr/simgrid/3.8.1/ref_guide/html/index.html) (hint: use the
-search field to access directly the function you are looking for):
+To this end you may need the following MSG functions (click on the links
+to see their descriptions):
 
 ~~~~{.c}
-int MSG_get_host_number (void)
+int MSG_get_host_number(void);
 xbt_dynar_t MSG_hosts_as_dynar(void);
 void * xbt_dynar_to_array (xbt_dynar_t dynar);
 msg_process_t MSG_process_create(const char *name, xbt_main_func_t code,
                                  void *data, msg_host_t host);
 ~~~~
 
-Note that it may avoid bugs later to avoid launching a worker on
-the master host so you probably want to remove it from the host
-list.
+\note
+    It may avoid bugs later to avoid launching a worker on
+    the master host so you probably want to remove it from the host
+    list.
 
-The `data` field of the `MSG_process_create` can be used to pass
+The `data` field of the @ref MSG_process_create can be used to pass
 a channel name that will be private between master
 and workers (e.g., `master_name:worker_name`). Adding the
 `master_name` in the channel name will allow to easily have several
@@ -287,10 +296,10 @@ const char * MSG_host_get_name(msg_host_t host);
 msg_process_t MSG_process_self(void);
 void * MSG_process_get_data(msg_process_t process);
 ~~~~
-   
-Again, you should check the [online documentation](http://simgrid.gforge.inria.fr/simgrid/3.8.1/ref_guide/html/index.html)
-for more information.  If you are not too much familiar with string
+
+If you are not too familiar with string
 manipulation in C, you may want to use the following functions
+(see the C reference for details):
 
 ~~~~{.c}
 char *strcpy(char *dest, const char *src);
@@ -299,18 +308,18 @@ char *strcat(char *dest, const char *src);
 
 ## Setting up a Time Limit Mechanism
 
-In the current version, the number of tasks is defined in the
+In the current version, the number of tasks is defined through the
 worker arguments. Hence, tasks are created at the very beginning of
 the simulation. Instead, create tasks as needed and provide a time
 limit indicating when it stops sending tasks. To this end, you will
-obviously need to know what time it is ([reference manual][fn:7]):
+obviously need to know what time it is:
 
 ~~~~{.c}
 double MSG_get_clock(void);
 ~~~~
 
 Otherwise, a quite effective way of terminating the simulation
-would be to use some of the following [function][fn:7]:
+would be to use some of the following functions:
 
 ~~~~{.c}
 void MSG_process_kill(msg_process_t process);
@@ -344,7 +353,7 @@ tasks processed). These debug messages can be activated as follows:
 
 SimGrid can trace all resource consumption and the outcome can be
 displayed with viva as illustrated in the section "Setting up and Compiling". However, when several
-masters are deployed, it is hard to understand what happens. 
+masters are deployed, it is hard to understand what happens.
 
 ~~~~{.xml}
 <?xml version='1.0'?>
@@ -368,14 +377,13 @@ masters are deployed, it is hard to understand what happens.
 </platform>
 ~~~~
 
-So let's use categories to track more precisely who does what and
-[when][fn:7].
+So let's use categories to track more precisely who does what and when:
 
 ~~~~{.c}
 void TRACE_category(const char *category);
 void MSG_task_set_category (msg_task_t task, const char *category);
 ~~~~
-   
+
 The outcome can then be visualized as follows:
 
 ~~~~{.sh}
@@ -476,7 +484,6 @@ bytes that you manage to distribute and process in one hour on
 [fn:4]: http://simgrid.gforge.inria.fr/documentation.html
 [fn:5]: http://paje.sourceforge.net/
 [fn:6]: http://vite.gforge.inria.fr/
-[fn:7]: http://simgrid.gforge.inria.fr/simgrid/3.8.1/ref_guide/html/index.html
 
 
 
index bf22827..01b3c6a 100644 (file)
@@ -1,6 +1,6 @@
 #! ./tesh
 
-$ ${bindir:=.}/io/file ${srcdir:=.}/examples/platforms/storage.xml "--log=root.fmt:[%10.6r]%e(%i:%P@%h)%e%m%n"
+$ ${bindir:=.}/io/file ${srcdir:=.}/examples/platforms/storage/storage.xml "--log=root.fmt:[%10.6r]%e(%i:%P@%h)%e%m%n"
 > [  0.000000] (0:@) Number of host '4'
 > [  0.000000] (2:1@alice)     Open file 'c:\Windows\setupact.log'
 > [  0.000000] (3:2@carl)      Open file '/home/doc/simgrid/examples/platforms/g5k_cabinets.xml'
@@ -55,7 +55,7 @@ $ ${bindir:=.}/io/file ${srcdir:=.}/examples/platforms/storage.xml "--log=root.f
 > [  0.008326] (3:2@carl)      Close file '/home/doc/simgrid/examples/platforms/g5k_cabinets.xml'
 > [  0.008326] (0:@) Simulation time 0.00832645
 
-$ ${bindir:=.}/io/file_unlink ${srcdir:=.}/examples/platforms/storage.xml "--log=root.fmt:[%10.6r]%e(%i:%P@%h)%e%m%n"
+$ ${bindir:=.}/io/file_unlink ${srcdir:=.}/examples/platforms/storage/storage.xml "--log=root.fmt:[%10.6r]%e(%i:%P@%h)%e%m%n"
 > [  0.000000] (0:@) Number of host '4'
 > [  0.000000] (1:0@denise)    Open file '/home/doc/simgrid/examples/platforms/g5k.xml'
 > [  0.000000] (1:0@denise)    Unlink file '/home/doc/simgrid/examples/platforms/g5k.xml'
index ddc15bc..e3ca838 100644 (file)
@@ -1,6 +1,6 @@
 #! ./tesh
 
-$ ${bindir:=.}/io/remote$EXEEXT ${srcdir:=.}/examples/platforms/remote_io.xml ${srcdir:=.}/examples/platforms/deployment_remote_io.xml "--log=root.fmt:[%10.6r]%e(%i@%5h)%e%m%n"
+$ ${bindir:=.}/io/remote$EXEEXT ${srcdir:=.}/examples/platforms/storage/remote_io.xml ${srcdir:=.}/examples/platforms/storage/remote_io.deployment.xml "--log=root.fmt:[%10.6r]%e(%i@%5h)%e%m%n"
 > [  0.000000] (0@     ) Init: 12 MiB used on 'Disk1'
 > [  0.000000] (0@     ) Init: 2280 MiB used on 'Disk2'
 > [  0.000000] (1@alice) Opened file 'c:\Windows\setupact.log'
index 93393fc..00412a4 100644 (file)
@@ -1,6 +1,6 @@
 #! ./tesh
 
-$ ${bindir:=.}/io/storage$EXEEXT ${srcdir:=.}/examples/platforms/storage.xml "--log=root.fmt:[%10.6r]%e(%i:%P@%h)%e%m%n"
+$ ${bindir:=.}/io/storage$EXEEXT ${srcdir:=.}/examples/platforms/storage/storage.xml "--log=root.fmt:[%10.6r]%e(%i:%P@%h)%e%m%n"
 > [  0.000000] (1:(null)@denise) *** Storage info on denise ***
 > [  0.000000] (1:(null)@denise) Storage name: Disk2, mount name: c:
 > [  0.000000] (1:(null)@denise) Total size: 536870912000 bytes
similarity index 64%
rename from examples/platforms/storage.xml
rename to examples/platforms/storage/storage.xml
index 988e40b..c26b204 100644 (file)
@@ -2,26 +2,26 @@
 <!DOCTYPE platform SYSTEM "http://simgrid.gforge.inria.fr/simgrid.dtd">
 
 <platform version="3">
-
-<config>
-  <prop id="path" value="../examples/platforms/"/>
-</config>
+  <config>
+    <prop id="path" value="../examples/platforms/"/>
+  </config>
 
   <AS id="AS0" routing="Full">
 
-   <storage_type id="single_HDD" model="linear_no_lat" 
-                 content="content/storage_content.txt" size="500GiB"
-                 content_type="txt_unix">
-      <model_prop id="Bwrite" value="30MBps" />
-      <model_prop id="Bread" value="100MBps" />
-      <model_prop id="Bconnection" value="120MBps" />
-   </storage_type>
-
-   <storage_type id="single_SSD" model="linear_no_lat" size="500GiB">
-      <model_prop id="Bwrite" value="60MBps" />
-      <model_prop id="Bread" value="200MBps" />
-      <model_prop id="Bconnection" value="220MBps" />
-   </storage_type>
+    <storage_type id="single_HDD" model="linear_no_lat" 
+                  content="content/storage_content.txt" size="500GiB"
+                  content_type="txt_unix">
+       <model_prop id="Bwrite" value="30MBps" />
+       <model_prop id="Bread" value="100MBps" />
+       <model_prop id="Bconnection" value="120MBps" />
+    </storage_type>
+
+    <storage_type id="single_SSD" model="linear_no_lat" size="500GiB"
+                  content="content/storage_content.txt" content_type="txt_unix">
+       <model_prop id="Bwrite" value="60MBps" />
+       <model_prop id="Bread" value="200MBps" />
+       <model_prop id="Bconnection" value="220MBps" />
+    </storage_type>
 
     <storage id="Disk1" typeId="single_HDD" attach="bob" />
     <storage id="Disk2" typeId="single_SSD"
index 2f2ceed..7e17983 100644 (file)
@@ -1,6 +1,6 @@
 #! ./tesh
 
-$ ${bindir:=.}/io/sd_io ${srcdir:=.}/examples/platforms/storage.xml 
+$ ${bindir:=.}/io/sd_io ${srcdir:=.}/examples/platforms/storage/storage.xml 
 > [0.000000] [sd_io/INFO] Workstation 'denise' mounts 'c:'
 > [0.000000] [sd_io/INFO] Workstation 'denise' mounts '/home'
 > [0.000000] [sd_io/INFO] Workstation 'alice' mounts 'c:'
index 15b877d..53e1214 100644 (file)
@@ -6,33 +6,45 @@
 /* This program is free software; you can redistribute it and/or modify it
  * under the terms of the license (GNU LGPL) which comes with this package. */
 
+/** \file modelchecker.h
+ *
+ *  This is the API used by the user simulated program to communicate
+ *  with the MC.
+ */
+
+#ifndef SIMGRID_MODELCHECKER_H
+#define SIMGRID_MODELCHECKER_H
+
 #include <stdbool.h>
 
 #include <simgrid_config.h> /* HAVE_MC ? */
 #include <xbt.h>
 #include "xbt/automaton.h"
 
-#ifndef SIMGRID_MODELCHECKER_H
-#define SIMGRID_MODELCHECKER_H
-
 SG_BEGIN_DECL()
 
 XBT_PUBLIC(int) MC_random(int min, int max);
 
 #ifdef HAVE_MC
 
-extern int _sg_do_model_check; /* please don't use directly: we inline MC_is_active, but that's what you should use */
+/* Internal variable used to check if we're running under the MC
+ *
+ * Please don't use directly: you should use MC_is_active. */
+extern int _sg_do_model_check;
 extern int _sg_mc_visited;
 
 #define MC_is_active()                  _sg_do_model_check
 #define MC_visited_reduction()          _sg_mc_visited
 
+/** Assertion for the model-checker
+ *
+ *  This function is used to define safety properties to verify.
+ */
 XBT_PUBLIC(void) MC_assert(int);
+
 XBT_PUBLIC(void) MC_automaton_new_propositional_symbol(const char* id, int(*fct)(void));
 XBT_PUBLIC(void) MC_automaton_new_propositional_symbol_pointer(const char *id, int* value);
-XBT_PUBLIC(void) MC_automaton_new_propositional_symbol_callback(const char* id,
-  xbt_automaton_propositional_symbol_callback_type callback,
-  void* data, xbt_automaton_propositional_symbol_free_function_type free_function);
+
 XBT_PUBLIC(void *) MC_snapshot(void);
 XBT_PUBLIC(int) MC_compare_snapshots(void *s1, void *s2);
 XBT_PUBLIC(void) MC_cut(void);
@@ -46,8 +58,6 @@ XBT_PUBLIC(void) MC_ignore(void *addr, size_t size);
 #define MC_assert(a)                    xbt_assert(a)
 #define MC_automaton_new_propositional_symbol(a, b) ((void)0)
 #define MC_automaton_new_propositional_symbol_pointer(a, b) ((void)0)
-#define MC_automaton_new_propositional_symbol_callback(id,callback,data,free_function) \
-  if(free_function) free_function(data);
 #define MC_snapshot()                   ((void*)0)
 #define MC_compare_snapshots(a, b)      0
 #define MC_cut()                        ((void)0)
index d19beb3..8a0a95f 100644 (file)
@@ -124,16 +124,9 @@ typedef struct {
 } s_sg_platf_host_cbarg_t, *sg_platf_host_cbarg_t;
 
 #define SG_PLATF_HOST_INITIALIZER { \
-    .id = NULL,\
-    .power_peak = 0,\
-    .core_amount = 1.,\
-    .power_scale = 1,\
-    .initial_state = SURF_RESOURCE_ON,\
-    .power_trace = NULL,\
-    .state_trace = NULL,\
-    .coord = NULL,\
-    .properties = NULL\
-    }
+    NULL, 0, 1, 1, 1., NULL, SURF_RESOURCE_ON, NULL, \
+    NULL, NULL \
+}
 
 typedef struct {
   const char* id;
@@ -163,15 +156,8 @@ typedef struct {
 } s_sg_platf_link_cbarg_t, *sg_platf_link_cbarg_t;
 
 #define SG_PLATF_LINK_INITIALIZER {\
-  .id = NULL,\
-  .bandwidth = 0.,\
-  .bandwidth_trace = NULL,\
-  .latency = 0.,\
-  .latency_trace = NULL,\
-  .state = SURF_RESOURCE_ON,\
-  .state_trace = NULL,\
-  .policy = SURF_LINK_SHARED,\
-  .properties = NULL\
+  NULL, 0., NULL, 0., NULL, SURF_RESOURCE_ON, \
+  NULL, SURF_LINK_SHARED, NULL \
 }
 
 typedef struct s_sg_platf_peer_cbarg *sg_platf_peer_cbarg_t;
@@ -186,7 +172,7 @@ typedef struct s_sg_platf_peer_cbarg {
   tmgr_trace_t state_trace;
 } s_sg_platf_peer_cbarg_t;
 
-#define SG_PLATF_PEER_INITIALIZER {NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}
+#define SG_PLATF_PEER_INITIALIZER {NULL,0.0,0.0,0.0,0.0,NULL,NULL,NULL}
 
 typedef struct s_sg_platf_route_cbarg *sg_platf_route_cbarg_t;
 typedef struct s_sg_platf_route_cbarg {
@@ -198,7 +184,7 @@ typedef struct s_sg_platf_route_cbarg {
   xbt_dynar_t link_list;
 } s_sg_platf_route_cbarg_t;
 
-#define SG_PLATF_ROUTE_INITIALIZER {TRUE,NULL,NULL,NULL,NULL,NULL}
+#define SG_PLATF_ROUTE_INITIALIZER {1,NULL,NULL,NULL,NULL,NULL}
 
 typedef struct s_sg_platf_cluster_cbarg *sg_platf_cluster_cbarg_t;
 typedef struct s_sg_platf_cluster_cbarg {
@@ -225,8 +211,11 @@ typedef struct s_sg_platf_cluster_cbarg {
   const char* state_trace;
 } s_sg_platf_cluster_cbarg_t;
 
-#define SG_PLATF_CLUSTER_INITIALIZER {NULL,NULL,NULL,NULL,NULL,NULL \
-  ,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}
+#define SG_PLATF_CLUSTER_INITIALIZER {NULL,NULL,NULL,NULL,0.0,1 \
+  ,1.,1.,0.,0.,0.,0.,0. \
+  ,SURF_CLUSTER_FLAT,NULL,NULL,NULL, \
+  SURF_LINK_SHARED,SURF_LINK_SHARED,NULL \
+  ,NULL}
 
 typedef struct s_sg_platf_cabinet_cbarg *sg_platf_cabinet_cbarg_t;
 typedef struct s_sg_platf_cabinet_cbarg {
@@ -239,7 +228,7 @@ typedef struct s_sg_platf_cabinet_cbarg {
   double lat;
 } s_sg_platf_cabinet_cbarg_t;
 
-#define SG_PLATF_CABINET_INITIALIZER {NULL,NULL,NULL,NULL,NULL,NULL,NULL}
+#define SG_PLATF_CABINET_INITIALIZER {NULL,NULL,NULL,NULL,0.0,0.0,0.0}
 
 typedef struct {
   const char* id;
@@ -250,7 +239,7 @@ typedef struct {
   const char* attach;
 } s_sg_platf_storage_cbarg_t, *sg_platf_storage_cbarg_t;
 
-#define SG_PLATF_STORAGE_INITIALIZER {NULL,NULL,NULL,NULL}
+#define SG_PLATF_STORAGE_INITIALIZER {NULL,NULL,NULL,NULL,NULL,NULL}
 
 typedef struct {
   const char* id;
@@ -262,7 +251,7 @@ typedef struct {
   sg_size_t size;
 } s_sg_platf_storage_type_cbarg_t, *sg_platf_storage_type_cbarg_t;
 
-#define SG_PLATF_STORAGE_TYPE_INITIALIZER {NULL,NULL,NULL,NULL,NULL}
+#define SG_PLATF_STORAGE_TYPE_INITIALIZER {NULL,NULL,NULL,NULL,NULL,NULL}
 
 typedef struct {
   const char* type_id;
@@ -294,7 +283,7 @@ typedef struct s_sg_platf_trace_cbarg {
   const char *pc_data;
 } s_sg_platf_trace_cbarg_t;
 
-#define SG_PLATF_TRACE_INITIALIZER {NULL,NULL,NULL,NULL}
+#define SG_PLATF_TRACE_INITIALIZER {NULL,NULL,0.0,NULL}
 
 typedef struct s_sg_platf_trace_connect_cbarg *sg_platf_trace_connect_cbarg_t;
 typedef struct s_sg_platf_trace_connect_cbarg {
@@ -303,7 +292,7 @@ typedef struct s_sg_platf_trace_connect_cbarg {
   const char *element;
 } s_sg_platf_trace_connect_cbarg_t;
 
-#define SG_PLATF_TRACE_CONNECT_INITIALIZER {NULL,NULL,NULL}
+#define SG_PLATF_TRACE_CONNECT_INITIALIZER {SURF_TRACE_CONNECT_KIND_LATENCY,NULL,NULL}
 
 typedef struct s_sg_platf_process_cbarg *sg_platf_process_cbarg_t;
 typedef struct s_sg_platf_process_cbarg {
diff --git a/include/xbt/automaton.hpp b/include/xbt/automaton.hpp
new file mode 100644 (file)
index 0000000..8b3827d
--- /dev/null
@@ -0,0 +1,38 @@
+/* Copyright (c) 2015. The SimGrid Team.
+ * All rights reserved.                                                     */
+
+/* This program is free software; you can redistribute it and/or modify it
+ * under the terms of the license (GNU LGPL) which comes with this package. */
+
+#ifndef _XBT_AUTOMATON_HPP
+#define _XBT_AUTOMATON_HPP
+
+#include <utility>
+
+#include <xbt/automaton.h>
+
+namespace simgrid {
+namespace xbt {
+
+/** Add a proposition to an automaton (the C++ way)
+ *
+ *  This API hides all the callback and dynamic allocation hell from
+ *  the used which can use C++ style functors and lambda expressions.
+ */
+template<class F>
+xbt_automaton_propositional_symbol_t add_proposition(
+  xbt_automaton_t a, const char* id, F f)
+{
+  F* callback = new F(std::move(f));
+  return xbt_automaton_propositional_symbol_new_callback(
+    a, id,
+    [](void* callback) -> int { return (*(F*)callback)(); },
+    callback,
+    [](void* callback) -> void { delete (F*)callback; }
+  );
+}
+
+}
+}
+
+#endif
index 33ad322..9378841 100644 (file)
@@ -67,12 +67,10 @@ XBT_PUBLIC( xbt_mheap_t ) mmalloc_get_default_md(void);
 xbt_mheap_t mmalloc_set_current_heap(xbt_mheap_t new_heap);
 xbt_mheap_t mmalloc_get_current_heap(void);
 
-struct s_dw_type;
-
 int mmalloc_compare_heap(mc_snapshot_t snapshot1, mc_snapshot_t snapshot2);
 int mmalloc_linear_compare_heap(xbt_mheap_t heap1, xbt_mheap_t heap2);
 int init_heap_information(xbt_mheap_t heap1, xbt_mheap_t heap2, xbt_dynar_t to_ignore1, xbt_dynar_t to_ignore2);
-int compare_heap_area(int process_index, const void *area1, const void* area2, mc_snapshot_t snapshot1, mc_snapshot_t snapshot2, xbt_dynar_t previous, struct s_dw_type *type, int pointer_level);
+int compare_heap_area(int process_index, const void *area1, const void* area2, mc_snapshot_t snapshot1, mc_snapshot_t snapshot2, xbt_dynar_t previous, mc_type_t type, int pointer_level);
 void reset_heap_information(void);
 
 size_t mmalloc_get_bytes_used(xbt_mheap_t);
index fae839c..48476d9 100644 (file)
 #ifndef _XBT_SYSDEP_H
 #define _XBT_SYSDEP_H
 
+#ifdef __cplusplus
+#include <type_traits>
+#endif
+
 #include "xbt/log.h"
 #include "xbt/misc.h"
 #include "xbt/asserts.h"
@@ -149,15 +153,44 @@ XBT_PUBLIC(void) xbt_free_f(void *p);
 /** @brief should be given a pointer to pointer, and frees the second one */
 XBT_PUBLIC(void) xbt_free_ref(void *d);
 
+SG_END_DECL()
+
 /** @brief like calloc, but xbt_die() on error and don't memset to 0
     @hideinitializer */
+#ifndef __cplusplus
+
 #define xbt_new(type, count)  ((type*)xbt_malloc (sizeof (type) * (count)))
 /** @brief like calloc, but xbt_die() on error
     @hideinitializer */
 #define xbt_new0(type, count) ((type*)xbt_malloc0 (sizeof (type) * (count)))
 
-/** @} */
+#else
 
+/** C++ wrapper for xtb_new
+ *
+ *  This ensures that we do not xbt_new things that need a constructor.
+ */
+template<typename T> inline
+T* xbt_new_(size_t count)
+{
+  static_assert(std::is_trivial<T>(),
+    "Cannot xbt_new this type");
+  return (T*) xbt_malloc(sizeof(T) * count);
+}
+
+template<typename T> inline
+T* xbt_new0_(size_t count)
+{
+  static_assert(std::is_trivial<T>(),
+    "Cannot xbt_new0 this type");
+  return (T*) xbt_malloc0(sizeof(T) * count);
+}
+
+#define xbt_new(type, count)  ::xbt_new_<type>(count)
+#define xbt_new0(type, count) ::xbt_new0_<type>(count)
+
+#endif
+
+/** @} */
 
-SG_END_DECL()
 #endif                          /* _XBT_SYSDEP_H */
index ea260c2..fb1cddf 100644 (file)
@@ -14,7 +14,7 @@
 
 #include <stdint.h>
 
-#include "mc_forward.h"
+#include "mc_forward.hpp"
 
 namespace simgrid {
 namespace mc {
index fe50841..d397d8f 100644 (file)
@@ -10,9 +10,9 @@
 #include <sys/types.h>
 
 #include <simgrid_config.h>
-#include <xbt/dynar.h>
+#include <xbt/dict.h>
 
-#include "mc_forward.h"
+#include "mc_forward.hpp"
 #include "mc_process.h"
 #include "PageStore.hpp"
 #include "mc_protocol.h"
@@ -32,14 +32,14 @@ class ModelChecker {
   // TODO, use std::unordered_set with heterogeneous comparison lookup (C++14)
   xbt_dict_t /* <hostname, NULL> */ hostnames_;
   // This is the parent snapshot of the current state:
-  s_mc_pages_store_t page_store_;
-  s_mc_process_t process_;
+  PageStore page_store_;
+  Process process_;
 public:
   ModelChecker(ModelChecker const&) = delete;
   ModelChecker& operator=(ModelChecker const&) = delete;
   ModelChecker(pid_t pid, int socket);
   ~ModelChecker();
-  s_mc_process_t& process()
+  Process& process()
   {
     return process_;
   }
index e8c74ac..5be3176 100644 (file)
@@ -36,12 +36,12 @@ namespace mc {
 static inline  __attribute__ ((always_inline))
 PageStore::hash_type mc_hash_page(const void* data)
 {
-  const uint64_t* values = (const uint64_t*) data;
-  size_t n = xbt_pagesize / sizeof(uint64_t);
+  const std::uint64_t* values = (const uint64_t*) data;
+  std::size_t n = xbt_pagesize / sizeof(uint64_t);
 
   // This djb2:
-  uint64_t hash = 5381;
-  for (size_t i=0; i!=n; ++i) {
+  std::uint64_t hash = 5381;
+  for (std::size_t i = 0; i != n; ++i) {
     hash = ((hash << 5) + hash) + values[i];
   }
   return hash;
@@ -55,8 +55,8 @@ PageStore::PageStore(size_t size) :
   // Using mmap in order to be able to expand the region
   // by relocating it somewhere else in the virtual memory
   // space:
-  void * memory = ::mmap(NULL, size << xbt_pagebits, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS|MAP_POPULATE, -1, 0);
-  if (memory==MAP_FAILED) {
+  void* memory = ::mmap(NULL, size << xbt_pagebits, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS|MAP_POPULATE, -1, 0);
+  if (memory == MAP_FAILED) {
     xbt_die("Could not mmap initial snapshot pages.");
   }
 
@@ -71,7 +71,7 @@ PageStore::~PageStore()
   ::munmap(this->memory_, this->capacity_ << xbt_pagebits);
 }
 
-void PageStore::resize(size_t size)
+void PageStore::resize(std::size_t size)
 {
   size_t old_bytesize = this->capacity_ << xbt_pagebits;
   size_t new_bytesize = size << xbt_pagebits;
@@ -92,7 +92,7 @@ void PageStore::resize(size_t size)
  *
  *  @return index of the free page
  */
-size_t PageStore::alloc_page()
+std::size_t PageStore::alloc_page()
 {
   if (this->free_pages_.empty()) {
 
@@ -115,7 +115,7 @@ size_t PageStore::alloc_page()
   }
 }
 
-void PageStore::remove_page(size_t pageno)
+void PageStore::remove_page(std::size_t pageno)
 {
   this->free_pages_.push_back(pageno);
   const void* page = this->get_page(pageno);
@@ -124,7 +124,7 @@ void PageStore::remove_page(size_t pageno)
 }
 
 /** Store a page in memory */
-size_t PageStore::store_page(void* page)
+std::size_t PageStore::store_page(void* page)
 {
   xbt_assert(top_index_ <= this->capacity_, "top_index is not consistent");
 
@@ -151,7 +151,7 @@ size_t PageStore::store_page(void* page)
 
   // Otherwise, a new page is allocated in the page store and the content
   // of the page is `memcpy()`-ed to this new page.
-  size_t pageno = alloc_page();
+  std::size_t pageno = alloc_page();
   xbt_assert(this->page_counts_[pageno]==0, "Allocated page is already used");
   void* snapshot_page = (void*) this->get_page(pageno);
   memcpy(snapshot_page, page, xbt_pagesize);
@@ -165,9 +165,9 @@ size_t PageStore::store_page(void* page)
 
 #ifdef SIMGRID_TEST
 
-#include <string.h>
-#include <stdlib.h>
-#include <stdint.h>
+#include <cstring>
+#include <cstdint>
+
 #include <unistd.h>
 #include <sys/mman.h>
 
@@ -177,9 +177,9 @@ size_t PageStore::store_page(void* page)
 
 static int value = 0;
 
-static void new_content(void* data, size_t size)
+static void new_content(void* data, std::size_t size)
 {
-  memset(data, ++value, size);
+  ::memset(data, ++value, size);
 }
 
 static void* getpage()
@@ -193,10 +193,12 @@ XBT_TEST_SUITE("mc_page_store", "Page store");
 
 XBT_TEST_UNIT("base", test_mc_page_store, "Test adding/removing pages in the store")
 {
+  using simgrid::mc::PageStore;
+  
   xbt_test_add("Init");
-  size_t pagesize = (size_t) getpagesize();
-  std::unique_ptr<simgrid::mc::PageStore> store
-    = std::unique_ptr<simgrid::mc::PageStore>(new simgrid::mc::PageStore(500));
+  std::size_t pagesize = (size_t) getpagesize();
+  std::unique_ptr<PageStore> store
+    = std::unique_ptr<PageStore>(new simgrid::mc::PageStore(500));
   void* data = getpage();
   xbt_test_assert(store->size()==0, "Bad size");
 
@@ -205,7 +207,7 @@ XBT_TEST_UNIT("base", test_mc_page_store, "Test adding/removing pages in the sto
   size_t pageno1 = store->store_page(data);
   xbt_test_assert(store->get_ref(pageno1)==1, "Bad refcount");
   const void* copy = store->get_page(pageno1);
-  xbt_test_assert(memcmp(data, copy, pagesize)==0, "Page data should be the same");
+  xbt_test_assert(::memcmp(data, copy, pagesize)==0, "Page data should be the same");
   xbt_test_assert(store->size()==1, "Bad size");
 
   xbt_test_add("Store the same page again");
index 9296a32..5dee482 100644 (file)
@@ -7,19 +7,14 @@
 #ifndef SIMGRID_MC_PAGESTORE_HPP
 #define SIMGRID_MC_PAGESTORE_HPP
 
-#include <stdint.h>
-
+#include <cstdint>
 #include <vector>
 
-#include <boost/array.hpp>
-#include <boost/utility.hpp>
 #include <boost/unordered_map.hpp>
 #include <boost/unordered_set.hpp>
 
-#include <xbt.h>
-
 #include "mc_mmu.h"
-#include "mc_forward.h"
+#include "mc_forward.hpp"
 
 namespace simgrid {
 namespace mc {
@@ -78,40 +73,37 @@ namespace mc {
  */
 class PageStore {
 public: // Types
-  typedef uint64_t hash_type;
+  typedef std::uint64_t hash_type;
 private: // Types
   // We are using a cheap hash to index a page.
   // We should expect collision and we need to associate multiple page indices
   // to the same hash.
-  typedef boost::unordered_set<size_t> page_set_type;
+  typedef boost::unordered_set<std::size_t> page_set_type;
   typedef boost::unordered_map<hash_type, page_set_type> pages_map_type;
 
 private: // Fields:
-  /** First page
-   *
-   *  mc_page_store_get_page expects that this is the first field.
-   * */
+  /** First page */
   void* memory_;
   /** Number of available pages in virtual memory */
-  size_t capacity_;
+  std::size_t capacity_;
   /** Top of the used pages (index of the next available page) */
-  size_t top_index_;
+  std::size_t top_index_;
   /** Page reference count */
-  std::vector<uint64_t> page_counts_;
+  std::vector<std::uint64_t> page_counts_;
   /** Index of available pages before the top */
-  std::vector<size_t> free_pages_;
+  std::vector<std::size_t> free_pages_;
   /** Index from page hash to page index */
   pages_map_type hash_index_;
 
 private: // Methods
-  void resize(size_t size);
-  size_t alloc_page();
-  void remove_page(size_t pageno);
+  void resize(std::size_t size);
+  std::size_t alloc_page();
+  void remove_page(std::size_t pageno);
 
 public: // Constructors
   PageStore(PageStore const&) = delete;
   PageStore& operator=(PageStore const&) = delete;
-  explicit PageStore(size_t size);
+  explicit PageStore(std::size_t size);
   ~PageStore();
 
 public: // Methods
@@ -125,7 +117,7 @@ public: // Methods
    * it is added to the `free_pages_` list and removed from the `hash_index_`.
    *
    * */
-  void unref_page(size_t pageno);
+  void unref_page(std::size_t pageno);
 
   /** @brief Increment the refcount for a given page
    *
@@ -147,43 +139,45 @@ public: // Methods
    *  @param Number of the memory page in the store
    *  @return Start of the page
    */
-  const void* get_page(size_t pageno) const;
+  const void* get_page(std::size_t pageno) const;
 
 public: // Debug/test methods
 
   /** @brief Get the number of references for a page */
-  size_t get_ref(size_t pageno);
+  std::size_t get_ref(std::size_t pageno);
 
   /** @brief Get the number of used pages */
-  size_t size();
+  std::size_t size();
 
   /** @brief Get the capacity of the page store
    *
    *  The capacity is expanded by a system call (mremap).
    * */
-  size_t capacity();
+  std::size_t capacity();
 
 };
 
 inline __attribute__((always_inline))
-void PageStore::unref_page(size_t pageno) {
-  if ((--this->page_counts_[pageno]) == 0) {
+void PageStore::unref_page(std::size_t pageno) {
+  if ((--this->page_counts_[pageno]) == 0)
     this->remove_page(pageno);
-  }
 }
 
 inline __attribute__((always_inline))
-void PageStore::ref_page(size_t pageno) {
+void PageStore::ref_page(size_t pageno)
+{
   ++this->page_counts_[pageno];
 }
 
 inline __attribute__((always_inline))
-const void* PageStore::get_page(size_t pageno) const {
+const void* PageStore::get_page(std::size_t pageno) const
+{
   return mc_page_from_number(this->memory_, pageno);
 }
 
 inline __attribute__((always_inline))
-size_t PageStore::get_ref(size_t pageno)  {
+std::size_t PageStore::get_ref(std::size_t pageno)
+{
   return this->page_counts_[pageno];
 }
 
@@ -193,7 +187,8 @@ size_t PageStore::size() {
 }
 
 inline __attribute__((always_inline))
-size_t PageStore::capacity() {
+std::size_t PageStore::capacity()
+{
   return this->capacity_;
 }
 
index 23853c8..4a6e63f 100644 (file)
@@ -56,7 +56,7 @@ RegionSnapshot region(
 RegionSnapshot sparse_region(RegionType region_type,
   void *start_addr, void* permanent_addr, size_t size)
 {
-  mc_process_t process = &mc_model_checker->process();
+  simgrid::mc::Process* process = &mc_model_checker->process();
 
   xbt_assert((((uintptr_t)start_addr) & (xbt_pagesize-1)) == 0,
     "Not at the beginning of a page");
index 5e09e62..9915186 100644 (file)
@@ -124,7 +124,7 @@ class RegionSnapshot {
 private:
   RegionType region_type_;
   StorageType storage_type_;
-  mc_object_info_t object_info_;
+  simgrid::mc::ObjectInformation* object_info_;
 
   /** @brief  Virtual address of the region in the simulated process */
   void *start_addr_;
@@ -251,8 +251,8 @@ public:
     return privatized_regions_;
   }
 
-  mc_object_info_t object_info() const { return object_info_; }
-  void object_info(mc_object_info_t info) { object_info_ = info; }
+  simgrid::mc::ObjectInformation* object_info() const { return object_info_; }
+  void object_info(simgrid::mc::ObjectInformation* info) { object_info_ = info; }
 
   // Other getters
 
index 24149db..54f04df 100644 (file)
@@ -46,22 +46,6 @@ XBT_LOG_NEW_DEFAULT_SUBCATEGORY(mc_checkpoint, mc,
 /************************************  Free functions **************************************/
 /*****************************************************************************************/
 
-static void MC_snapshot_stack_free_voidp(void *s)
-{
-  mc_snapshot_stack_t stack = (mc_snapshot_stack_t) * (void **) s;
-  delete stack;
-}
-
-static void local_variable_free_voidp(void *v)
-{
-  local_variable_t var = *(local_variable_t*)v;
-  delete var;
-}
-
-}
-
-extern "C" {
-
 /** @brief Restore a region from a snapshot
  *
  *  @param reg     Target region
@@ -132,7 +116,7 @@ extern "C" {
 
 static void MC_snapshot_add_region(int index, mc_snapshot_t snapshot,
                                   simgrid::mc::RegionType type,
-                                  mc_object_info_t object_info,
+                                  simgrid::mc::ObjectInformation* object_info,
                                   void *start_addr, void* permanent_addr, size_t size)
 {
   if (type == simgrid::mc::RegionType::Data)
@@ -140,7 +124,7 @@ static void MC_snapshot_add_region(int index, mc_snapshot_t snapshot,
   else if (type == simgrid::mc::RegionType::Heap)
     xbt_assert(!object_info, "Unexpected object info for heap region.");
 
-  const bool privatization_aware = MC_object_info_is_privatized(object_info);
+  const bool privatization_aware = object_info && object_info->privatized();
 
   simgrid::mc::RegionSnapshot region;
   if (privatization_aware && MC_smpi_process_count())
@@ -155,7 +139,7 @@ static void MC_snapshot_add_region(int index, mc_snapshot_t snapshot,
   return;
 }
 
-static void MC_get_memory_regions(mc_process_t process, mc_snapshot_t snapshot)
+static void MC_get_memory_regions(simgrid::mc::Process* process, mc_snapshot_t snapshot)
 {
   const size_t n = process->object_infos.size();
   snapshot->snapshot_regions.resize(n + 1);
@@ -196,9 +180,11 @@ static void MC_get_memory_regions(mc_process_t process, mc_snapshot_t snapshot)
  *
  *  `dl_iterate_phdr` would be more robust but would not work in cross-process.
  * */
-void MC_find_object_address(std::vector<simgrid::mc::VmMap> const& maps, mc_object_info_t result)
+void MC_find_object_address(
+  std::vector<simgrid::mc::VmMap> const& maps, simgrid::mc::ObjectInformation* result)
 {
-  const char *name = basename(result->file_name);
+  const char* file_name = xbt_strdup(result->file_name.c_str());
+  const char *name = basename(file_name);
   for (size_t i = 0; i < maps.size(); ++i) {
     simgrid::mc::VmMap const& reg = maps[i];
     if (maps[i].pathname.empty()
@@ -243,7 +229,6 @@ void MC_find_object_address(std::vector<simgrid::mc::VmMap> const& maps, mc_obje
   if (result->end_exec && (const void*) result->end_exec > result->end)
     result->end = result->end_exec;
 
-  xbt_assert(result->file_name);
   xbt_assert(result->start_rw);
   xbt_assert(result->start_exec);
 }
@@ -260,7 +245,7 @@ void MC_find_object_address(std::vector<simgrid::mc::VmMap> const& maps, mc_obje
  *  \param ip    Instruction pointer
  *  \return      true if the variable is valid
  * */
-static bool mc_valid_variable(dw_variable_t var, dw_frame_t scope,
+static bool mc_valid_variable(simgrid::mc::Variable* var, simgrid::mc::Frame* scope,
                               const void *ip)
 {
   // The variable is not yet valid:
@@ -271,20 +256,19 @@ static bool mc_valid_variable(dw_variable_t var, dw_frame_t scope,
 }
 
 static void mc_fill_local_variables_values(mc_stack_frame_t stack_frame,
-                                           dw_frame_t scope, int process_index,
+                                           simgrid::mc::Frame* scope, int process_index,
                                            std::vector<s_local_variable>& result)
 {
-  mc_process_t process = &mc_model_checker->process();
+  simgrid::mc::Process* process = &mc_model_checker->process();
 
   void *ip = (void *) stack_frame->ip;
   if (ip < scope->low_pc || ip >= scope->high_pc)
     return;
 
-  unsigned cursor = 0;
-  dw_variable_t current_variable;
-  xbt_dynar_foreach(scope->variables, cursor, current_variable) {
+  for(simgrid::mc::Variable& current_variable :
+      scope->variables) {
 
-    if (!mc_valid_variable(current_variable, scope, (void *) stack_frame->ip))
+    if (!mc_valid_variable(&current_variable, scope, (void *) stack_frame->ip))
       continue;
 
     int region_type;
@@ -297,18 +281,18 @@ static void mc_fill_local_variables_values(mc_stack_frame_t stack_frame,
     s_local_variable_t new_var;
     new_var.subprogram = stack_frame->frame;
     new_var.ip = stack_frame->ip;
-    new_var.name = current_variable->name;
-    new_var.type = current_variable->type;
+    new_var.name = current_variable.name;
+    new_var.type = current_variable.type;
     new_var.region = region_type;
     new_var.address = nullptr;
 
-    if (current_variable->address != NULL) {
-      new_var.address = current_variable->address;
-    } else if (current_variable->locations.size != 0) {
+    if (current_variable.address != NULL) {
+      new_var.address = current_variable.address;
+    } else if (!current_variable.location_list.empty()) {
       s_mc_location_t location;
       mc_dwarf_resolve_locations(
-        &location, &current_variable->locations,
-        current_variable->object_info,
+        &location, &current_variable.location_list,
+        current_variable.object_info,
         &(stack_frame->unw_cursor),
         (void *) stack_frame->frame_base,
         &mc_model_checker->process(), process_index);
@@ -330,10 +314,9 @@ static void mc_fill_local_variables_values(mc_stack_frame_t stack_frame,
   }
 
   // Recursive processing of nested scopes:
-  dw_frame_t nested_scope = NULL;
-  xbt_dynar_foreach(scope->scopes, cursor, nested_scope) {
-    mc_fill_local_variables_values(stack_frame, nested_scope, process_index, result);
-  }
+  for(simgrid::mc::Frame& nested_scope : scope->scopes)
+    mc_fill_local_variables_values(
+      stack_frame, &nested_scope, process_index, result);
 }
 
 static std::vector<s_local_variable> MC_get_local_variables_values(
@@ -353,7 +336,7 @@ static void MC_stack_frame_free_voipd(void *s)
 
 static std::vector<s_mc_stack_frame_t> MC_unwind_stack_frames(mc_unw_context_t stack_context)
 {
-  mc_process_t process = &mc_model_checker->process();
+  simgrid::mc::Process* process = &mc_model_checker->process();
   std::vector<s_mc_stack_frame_t> result;
 
   unw_cursor_t c;
@@ -380,7 +363,7 @@ static std::vector<s_mc_stack_frame_t> MC_unwind_stack_frames(mc_unw_context_t s
 
       // TODO, use real addresses in frame_t instead of fixing it here
 
-      dw_frame_t frame = process->find_function(remote(ip));
+      simgrid::mc::Frame* frame = process->find_function(remote(ip));
       stack_frame.frame = frame;
 
       if (frame) {
@@ -395,8 +378,8 @@ static std::vector<s_mc_stack_frame_t> MC_unwind_stack_frames(mc_unw_context_t s
       result.push_back(std::move(stack_frame));
 
       /* Stop before context switch with maestro */
-      if (frame != NULL && frame->name != NULL
-          && !strcmp(frame->name, "smx_ctx_sysv_wrapper"))
+      if (frame != nullptr &&
+          frame->name == "smx_ctx_sysv_wrapper")
         break;
 
       int ret = unw_step(&c);
@@ -586,7 +569,7 @@ mc_snapshot_t MC_take_snapshot(int num_state)
 {
   XBT_DEBUG("Taking snapshot %i", num_state);
 
-  mc_process_t mc_process = &mc_model_checker->process();
+  simgrid::mc::Process* mc_process = &mc_model_checker->process();
 
   mc_snapshot_t snapshot = new simgrid::mc::Snapshot();
 
index f48a80c..c80d9dd 100644 (file)
 #include "mc_client.h"
 #include "ModelChecker.hpp"
 
+/** \file mc_client_api.cpp
+ *
+ *  This is the implementation of the API used by the user simulated program to
+ *  communicate with the MC (declared in modelchecker.h).
+ */
+
 extern "C" {
 
 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(mc_client_api, mc,
@@ -55,13 +61,42 @@ void MC_cut(void)
 
 void MC_ignore(void* addr, size_t size)
 {
-  if (mc_mode == MC_MODE_CLIENT) {
-    s_mc_ignore_memory_message_t message;
-    message.type = MC_MESSAGE_IGNORE_MEMORY;
-    message.addr = (std::uintptr_t) addr;
-    message.size = size;
-    MC_client_send_message(&message, sizeof(message));
-  }
+  xbt_assert(mc_mode != MC_MODE_SERVER);
+  if (mc_mode != MC_MODE_CLIENT)
+    return;
+
+  s_mc_ignore_memory_message_t message;
+  message.type = MC_MESSAGE_IGNORE_MEMORY;
+  message.addr = (std::uintptr_t) addr;
+  message.size = size;
+  MC_client_send_message(&message, sizeof(message));
+}
+
+void MC_automaton_new_propositional_symbol(const char *id, int(*fct)(void))
+{
+  xbt_assert(mc_mode != MC_MODE_SERVER);
+  if (mc_mode != MC_MODE_CLIENT)
+    return;
+
+  xbt_die("Support for client-side function proposition is not implemented: "
+    "use MC_automaton_new_propositional_symbol_pointer instead."
+  );
+}
+
+void MC_automaton_new_propositional_symbol_pointer(const char *name, int* value)
+{
+  xbt_assert(mc_mode != MC_MODE_SERVER);
+  if (mc_mode != MC_MODE_CLIENT)
+    return;
+
+  s_mc_register_symbol_message_t message;
+  message.type = MC_MESSAGE_REGISTER_SYMBOL;
+  if (strlen(name) + 1 > sizeof(message.name))
+    xbt_die("Symbol is too long");
+  strncpy(message.name, name, sizeof(message.name));
+  message.callback = nullptr;
+  message.data = value;
+  MC_client_send_message(&message, sizeof(message));
 }
 
 }
index 39aaf87..9802a17 100644 (file)
@@ -104,12 +104,12 @@ static int compare_areas_with_type(struct mc_compare_state& state,
                                    int process_index,
                                    void* real_area1, mc_snapshot_t snapshot1, mc_mem_region_t region1,
                                    void* real_area2, mc_snapshot_t snapshot2, mc_mem_region_t region2,
-                                   dw_type_t type, int pointer_level)
+                                   simgrid::mc::Type* type, int pointer_level)
 {
-  mc_process_t process = &mc_model_checker->process();
+  simgrid::mc::Process* process = &mc_model_checker->process();
 
-  unsigned int cursor = 0;
-  dw_type_t member, subtype, subsubtype;
+  simgrid::mc::Type* subtype;
+  simgrid::mc::Type* subsubtype;
   int elm_size, i, res;
 
   top:
@@ -211,7 +211,7 @@ static int compare_areas_with_type(struct mc_compare_state& state,
       else if (region1->contain(simgrid::mc::remote(addr_pointed1))) {
         if (!region2->contain(simgrid::mc::remote(addr_pointed2)))
           return 1;
-        if (type->dw_type_id == NULL)
+        if (!type->type_id)
           return (addr_pointed1 != addr_pointed2);
         else {
           return compare_areas_with_type(state, process_index,
@@ -232,18 +232,18 @@ static int compare_areas_with_type(struct mc_compare_state& state,
   }
   case DW_TAG_structure_type:
   case DW_TAG_class_type:
-    xbt_dynar_foreach(type->members, cursor, member) {
+    for(simgrid::mc::Type& member : type->members) {
       void *member1 =
-        mc_member_resolve(real_area1, type, member, snapshot1, process_index);
+        mc_member_resolve(real_area1, type, &member, snapshot1, process_index);
       void *member2 =
-        mc_member_resolve(real_area2, type, member, snapshot2, process_index);
+        mc_member_resolve(real_area2, type, &member, snapshot2, process_index);
       mc_mem_region_t subregion1 = mc_get_region_hinted(member1, snapshot1, process_index, region1);
       mc_mem_region_t subregion2 = mc_get_region_hinted(member2, snapshot2, process_index, region2);
       res =
           compare_areas_with_type(state, process_index,
                                   member1, snapshot1, subregion1,
                                   member2, snapshot2, subregion2,
-                                  member->subtype, pointer_level);
+                                  member.subtype, pointer_level);
       if (res == 1)
         return res;
     }
@@ -259,7 +259,7 @@ static int compare_areas_with_type(struct mc_compare_state& state,
   return 0;
 }
 
-static int compare_global_variables(mc_object_info_t object_info,
+static int compare_global_variables(simgrid::mc::ObjectInformation* object_info,
                                     int process_index,
                                     mc_mem_region_t r1,
                                     mc_mem_region_t r2, mc_snapshot_t snapshot1,
@@ -295,32 +295,28 @@ static int compare_global_variables(mc_object_info_t object_info,
 
   struct mc_compare_state state;
 
-  xbt_dynar_t variables;
-  int res;
-  unsigned int cursor = 0;
-  dw_variable_t current_var;
+  std::vector<simgrid::mc::Variable>& variables = object_info->global_variables;
 
-  variables = object_info->global_variables;
-
-  xbt_dynar_foreach(variables, cursor, current_var) {
+  for (simgrid::mc::Variable& current_var : variables) {
 
     // If the variable is not in this object, skip it:
     // We do not expect to find a pointer to something which is not reachable
     // by the global variables.
-    if ((char *) current_var->address < (char *) object_info->start_rw
-        || (char *) current_var->address > (char *) object_info->end_rw)
+    if ((char *) current_var.address < (char *) object_info->start_rw
+        || (char *) current_var.address > (char *) object_info->end_rw)
       continue;
 
-    dw_type_t bvariable_type = current_var->type;
-    res =
+    simgrid::mc::Type* bvariable_type = current_var.type;
+    int res =
         compare_areas_with_type(state, process_index,
-                                (char *) current_var->address, snapshot1, r1,
-                                (char *) current_var->address, snapshot2, r2,
+                                (char *) current_var.address, snapshot1, r1,
+                                (char *) current_var.address, snapshot2, r2,
                                 bvariable_type, 0);
     if (res == 1) {
       XBT_TRACE3(mc, global_diff, -1, -1, current_var->name);
       XBT_VERB("Global variable %s (%p) is different between snapshots",
-               current_var->name, (char *) current_var->address);
+               current_var.name.c_str(),
+               (char *) current_var.address);
       return 1;
     }
 
@@ -353,15 +349,18 @@ static int compare_local_variables(int process_index,
           || current_var1->ip != current_var2->ip) {
         // TODO, fix current_varX->subprogram->name to include name if DW_TAG_inlined_subprogram
         XBT_VERB
-            ("Different name of variable (%s - %s) or frame (%s - %s) or ip (%lu - %lu)",
-             current_var1->name.c_str(), current_var2->name.c_str(),
-             current_var1->subprogram->name, current_var2->subprogram->name,
+            ("Different name of variable (%s - %s) "
+             "or frame (%s - %s) or ip (%lu - %lu)",
+             current_var1->name.c_str(),
+             current_var2->name.c_str(),
+             current_var1->subprogram->name.c_str(),
+             current_var2->subprogram->name.c_str(),
              current_var1->ip, current_var2->ip);
         return 1;
       }
       // TODO, fix current_varX->subprogram->name to include name if DW_TAG_inlined_subprogram
 
-        dw_type_t subtype = current_var1->type;
+        simgrid::mc::Type* subtype = current_var1->type;
         res =
             compare_areas_with_type(state, process_index,
                                     current_var1->address, snapshot1, mc_get_snapshot_region(current_var1->address, snapshot1, process_index),
@@ -372,9 +371,12 @@ static int compare_local_variables(int process_index,
         // TODO, fix current_varX->subprogram->name to include name if DW_TAG_inlined_subprogram
         XBT_TRACE3(mc, local_diff, -1, -1, current_var1->name);
         XBT_VERB
-            ("Local variable %s (%p - %p) in frame %s  is different between snapshots",
-             current_var1->name.c_str(), current_var1->address, current_var2->address,
-             current_var1->subprogram->name);
+            ("Local variable %s (%p - %p) in frame %s "
+             "is different between snapshots",
+             current_var1->name.c_str(),
+             current_var1->address,
+             current_var2->address,
+             current_var1->subprogram->name.c_str());
         return res;
       }
       cursor++;
@@ -385,7 +387,7 @@ static int compare_local_variables(int process_index,
 
 int snapshot_compare(void *state1, void *state2)
 {
-  mc_process_t process = &mc_model_checker->process();
+  simgrid::mc::Process* process = &mc_model_checker->process();
 
   mc_snapshot_t s1, s2;
   int num1, num2;
@@ -583,7 +585,7 @@ int snapshot_compare(void *state1, void *state2)
     xbt_assert(region1->object_info() == region2->object_info());
     xbt_assert(region1->object_info());
 
-    const char* name = region1->object_info()->file_name;
+    std::string const& name = region1->object_info()->file_name;
 
 #ifdef MC_DEBUG
     if (is_diff == 0)
@@ -603,13 +605,13 @@ int snapshot_compare(void *state1, void *state2)
       xbt_os_walltimer_stop(timer);
       mc_comp_times->global_variables_comparison_time
         += xbt_os_timer_elapsed(timer);
-      XBT_DEBUG("(%d - %d) Different global variables in %s", num1, num2,
-                name);
+      XBT_DEBUG("(%d - %d) Different global variables in %s",
+        num1, num2, name.c_str());
       errors++;
 #else
 #ifdef MC_VERBOSE
-      XBT_VERB("(%d - %d) Different global variables in %s", num1, num2,
-               name);
+      XBT_VERB("(%d - %d) Different global variables in %s",
+        num1, num2, name.c_str());
 #endif
 
       reset_heap_information();
index 06b1141..628bbb6 100644 (file)
@@ -151,7 +151,8 @@ struct s_mc_diff {
   std::vector<s_mc_heap_ignore_region_t>* to_ignore1;
   std::vector<s_mc_heap_ignore_region_t>* to_ignore2;
   s_heap_area_t *equals_to1, *equals_to2;
-  dw_type_t *types1, *types2;
+  simgrid::mc::Type **types1;
+  simgrid::mc::Type **types2;
   size_t available;
 };
 
@@ -380,18 +381,18 @@ int init_heap_information(xbt_mheap_t heap1, xbt_mheap_t heap2,
         realloc(state->equals_to1,
                 state->heaplimit * MAX_FRAGMENT_PER_BLOCK *
                 sizeof(s_heap_area_t));
-    state->types1 = (s_dw_type**)
+    state->types1 = (simgrid::mc::Type**)
         realloc(state->types1,
                 state->heaplimit * MAX_FRAGMENT_PER_BLOCK *
-                sizeof(type_name *));
+                sizeof(simgrid::mc::Type*));
     state->equals_to2 = (s_heap_area_t*)
         realloc(state->equals_to2,
                 state->heaplimit * MAX_FRAGMENT_PER_BLOCK *
                 sizeof(s_heap_area_t));
-    state->types2 = (s_dw_type**)
+    state->types2 = (simgrid::mc::Type**)
         realloc(state->types2,
                 state->heaplimit * MAX_FRAGMENT_PER_BLOCK *
-                sizeof(type_name *));
+                sizeof(simgrid::mc::Type*));
     state->available = state->heaplimit;
   }
 
@@ -430,7 +431,7 @@ mc_mem_region_t MC_get_heap_region(mc_snapshot_t snapshot)
 
 int mmalloc_compare_heap(mc_snapshot_t snapshot1, mc_snapshot_t snapshot2)
 {
-  mc_process_t process = &mc_model_checker->process();
+  simgrid::mc::Process* process = &mc_model_checker->process();
   struct s_mc_diff *state = mc_diff_info;
 
   /* Start comparison */
@@ -787,7 +788,7 @@ static int compare_heap_area_without_type(struct s_mc_diff *state, int process_i
                                           xbt_dynar_t previous, int size,
                                           int check_ignore)
 {
-  mc_process_t process = &mc_model_checker->process();
+  simgrid::mc::Process* process = &mc_model_checker->process();
 
   int i = 0;
   const void *addr_pointed1, *addr_pointed2;
@@ -875,7 +876,7 @@ static int compare_heap_area_with_type(struct s_mc_diff *state, int process_inde
                                        const void *real_area1, const void *real_area2,
                                        mc_snapshot_t snapshot1,
                                        mc_snapshot_t snapshot2,
-                                       xbt_dynar_t previous, dw_type_t type,
+                                       xbt_dynar_t previous, simgrid::mc::Type* type,
                                        int area_size, int check_ignore,
                                        int pointer_level)
 {
@@ -893,11 +894,9 @@ top:
     return 0;
   }
 
-  dw_type_t subtype, subsubtype;
+  simgrid::mc::Type *subtype, *subsubtype;
   int res, elm_size;
-  unsigned int cursor = 0;
-  dw_type_t member;
-  const void *addr_pointed1, *addr_pointed2;;
+  const void *addr_pointed1, *addr_pointed2;
 
   mc_mem_region_t heap_region1 = MC_get_heap_region(snapshot1);
   mc_mem_region_t heap_region2 = MC_get_heap_region(snapshot2);
@@ -907,7 +906,7 @@ top:
     return 1;
 
   case DW_TAG_base_type:
-    if (type->name != NULL && strcmp(type->name, "char") == 0) {        /* String, hence random (arbitrary ?) size */
+    if (!type->name.empty() && type->name == "char") {        /* String, hence random (arbitrary ?) size */
       if (real_area1 == real_area2)
         return -1;
       else
@@ -1042,17 +1041,16 @@ top:
         return -1;
       }
     } else {
-      cursor = 0;
-      xbt_dynar_foreach(type->members, cursor, member) {
+      for(simgrid::mc::Type& member : type->members) {
         // TODO, optimize this? (for the offset case)
         void *real_member1 =
-            mc_member_resolve(real_area1, type, member, (mc_address_space_t) snapshot1, process_index);
+            mc_member_resolve(real_area1, type, &member, (simgrid::mc::AddressSpace*) snapshot1, process_index);
         void *real_member2 =
-            mc_member_resolve(real_area2, type, member, (mc_address_space_t) snapshot2, process_index);
+            mc_member_resolve(real_area2, type, &member, (simgrid::mc::AddressSpace*) snapshot2, process_index);
         res =
             compare_heap_area_with_type(state, process_index, real_member1, real_member2,
                                         snapshot1, snapshot2,
-                                        previous, member->subtype, -1,
+                                        previous, member.subtype, -1,
                                         check_ignore, 0);
         if (res == 1) {
           return res;
@@ -1083,7 +1081,7 @@ top:
  * @param  area_size
  * @return                    DWARF type ID for given offset
  */
-static dw_type_t get_offset_type(void *real_base_address, dw_type_t type,
+static simgrid::mc::Type* get_offset_type(void *real_base_address, simgrid::mc::Type* type,
                                  int offset, int area_size,
                                  mc_snapshot_t snapshot, int process_index)
 {
@@ -1104,20 +1102,18 @@ static dw_type_t get_offset_type(void *real_base_address, dw_type_t type,
       else
         return NULL;
     } else {
-      unsigned int cursor = 0;
-      dw_type_t member;
-      xbt_dynar_foreach(type->members, cursor, member) {
+      for(simgrid::mc::Type& member : type->members) {
 
-        if (!member->location.size) {
+        if (member.has_offset_location()) {
           // We have the offset, use it directly (shortcut):
-          if (member->offset == offset)
-            return member->subtype;
+          if (member.offset() == offset)
+            return member.subtype;
         } else {
           void *real_member =
-            mc_member_resolve(real_base_address, type, member,
+            mc_member_resolve(real_base_address, type, &member,
               snapshot, process_index);
           if ((char*) real_member - (char *) real_base_address == offset)
-            return member->subtype;
+            return member.subtype;
         }
 
       }
@@ -1144,9 +1140,9 @@ static dw_type_t get_offset_type(void *real_base_address, dw_type_t type,
  */
 int compare_heap_area(int process_index, const void *area1, const void *area2, mc_snapshot_t snapshot1,
                       mc_snapshot_t snapshot2, xbt_dynar_t previous,
-                      dw_type_t type, int pointer_level)
+                      simgrid::mc::Type* type, int pointer_level)
 {
-  mc_process_t process = &mc_model_checker->process();
+  simgrid::mc::Process* process = &mc_model_checker->process();
 
   struct s_mc_diff *state = mc_diff_info;
 
@@ -1159,7 +1155,7 @@ int compare_heap_area(int process_index, const void *area1, const void *area2, m
   int type_size = -1;
   int offset1 = 0, offset2 = 0;
   int new_size1 = -1, new_size2 = -1;
-  dw_type_t new_type1 = NULL, new_type2 = NULL;
+  simgrid::mc::Type *new_type1 = NULL, *new_type2 = NULL;
 
   int match_pairs = 0;
 
@@ -1223,8 +1219,8 @@ int compare_heap_area(int process_index, const void *area1, const void *area2, m
 
     // Find type_size:
     if ((type->type == DW_TAG_pointer_type)
-        || ((type->type == DW_TAG_base_type) && type->name != NULL
-            && (!strcmp(type->name, "char"))))
+        || ((type->type == DW_TAG_base_type) && !type->name.empty()
+            && type->name == "char"))
       type_size = -1;
     else
       type_size = type->byte_size;
@@ -1272,7 +1268,7 @@ int compare_heap_area(int process_index, const void *area1, const void *area2, m
     if (type_size != -1) {
       if (type_size != (ssize_t) heapinfo1->busy_block.busy_size
           && type_size != (ssize_t)   heapinfo2->busy_block.busy_size
-          && (type->name == NULL || !strcmp(type->name, "struct s_smx_context"))) {
+          && (type->name.empty() || type->name == "struct s_smx_context")) {
         if (match_pairs) {
           match_equals(state, previous);
           xbt_dynar_free(&previous);
@@ -1573,27 +1569,6 @@ static int get_pointed_area_size(void *area, int heap)
   }
 }
 
-// Not used:
-char *get_type_description(mc_object_info_t info, char *type_name)
-{
-
-  xbt_dict_cursor_t dict_cursor;
-  char *type_origin;
-  dw_type_t type;
-
-  xbt_dict_foreach(info->types, dict_cursor, type_origin, type) {
-    if (type->name && (strcmp(type->name, type_name) == 0)
-        && type->byte_size > 0) {
-      xbt_dict_cursor_free(&dict_cursor);
-      return type_origin;
-    }
-  }
-
-  xbt_dict_cursor_free(&dict_cursor);
-  return NULL;
-}
-
-
 #ifndef max
 #define max( a, b ) ( ((a) > (b)) ? (a) : (b) )
 #endif
index ab65cae..0b0e2e4 100644 (file)
@@ -6,23 +6,24 @@
 
 #include <cinttypes>
 
+#include <algorithm>
+#include <memory>
+
 #include <stdlib.h>
 #define DW_LANG_Objc DW_LANG_ObjC       /* fix spelling error in older dwarf.h */
 #include <dwarf.h>
 #include <elfutils/libdw.h>
 
 #include <simgrid_config.h>
+#include <simgrid/util.hpp>
 #include <xbt/log.h>
 #include <xbt/sysdep.h>
 
+#include <simgrid/util.hpp>
+
 #include "mc_object_info.h"
 #include "mc_private.h"
 
-static void MC_dwarf_register_global_variable(mc_object_info_t info, dw_variable_t variable);
-static void MC_register_variable(mc_object_info_t info, dw_frame_t frame, dw_variable_t variable);
-static void MC_dwarf_register_non_global_variable(mc_object_info_t info, dw_frame_t frame, dw_variable_t variable);
-static void MC_dwarf_register_variable(mc_object_info_t info, dw_frame_t frame, dw_variable_t variable);
-
 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(mc_dwarf, mc, "DWARF processing");
 
 /** \brief The default DW_TAG_lower_bound for a given DW_AT_language.
@@ -60,14 +61,14 @@ static uint64_t MC_dwarf_array_element_count(Dwarf_Die * die, Dwarf_Die * unit);
  *  \param unit the DIE of the compile unit of the current DIE
  *  \param frame containg frame if any
  */
-static void MC_dwarf_handle_die(mc_object_info_t info, Dwarf_Die * die,
-                                Dwarf_Die * unit, dw_frame_t frame,
+static void MC_dwarf_handle_die(simgrid::mc::ObjectInformation* info, Dwarf_Die * die,
+                                Dwarf_Die * unit, simgrid::mc::Frame* frame,
                                 const char *ns);
 
 /** \brief Process a type DIE
  */
-static void MC_dwarf_handle_type_die(mc_object_info_t info, Dwarf_Die * die,
-                                     Dwarf_Die * unit, dw_frame_t frame,
+static void MC_dwarf_handle_type_die(simgrid::mc::ObjectInformation* info, Dwarf_Die * die,
+                                     Dwarf_Die * unit, simgrid::mc::Frame* frame,
                                      const char *ns);
 
 /** \brief Calls MC_dwarf_handle_die on all childrend of the given die
@@ -77,8 +78,8 @@ static void MC_dwarf_handle_type_die(mc_object_info_t info, Dwarf_Die * die,
  *  \param unit the DIE of the compile unit of the current DIE
  *  \param frame containg frame if any
  */
-static void MC_dwarf_handle_children(mc_object_info_t info, Dwarf_Die * die,
-                                     Dwarf_Die * unit, dw_frame_t frame,
+static void MC_dwarf_handle_children(simgrid::mc::ObjectInformation* info, Dwarf_Die * die,
+                                     Dwarf_Die * unit, simgrid::mc::Frame* frame,
                                      const char *ns);
 
 /** \brief Handle a variable (DW_TAG_variable or other)
@@ -88,8 +89,8 @@ static void MC_dwarf_handle_children(mc_object_info_t info, Dwarf_Die * die,
  *  \param unit the DIE of the compile unit of the current DIE
  *  \param frame containg frame if any
  */
-static void MC_dwarf_handle_variable_die(mc_object_info_t info, Dwarf_Die * die,
-                                         Dwarf_Die * unit, dw_frame_t frame,
+static void MC_dwarf_handle_variable_die(simgrid::mc::ObjectInformation* info, Dwarf_Die * die,
+                                         Dwarf_Die * unit, simgrid::mc::Frame* frame,
                                          const char *ns);
 
 /** \brief Get the DW_TAG_type of the DIE
@@ -97,7 +98,7 @@ static void MC_dwarf_handle_variable_die(mc_object_info_t info, Dwarf_Die * die,
  *  \param die DIE
  *  \return DW_TAG_type attribute as a new string (NULL if none)
  */
-static char *MC_dwarf_at_type(Dwarf_Die * die);
+static std::uint64_t MC_dwarf_at_type(Dwarf_Die * die);
 
 /** \brief A class of DWARF tags (DW_TAG_*)
  */
@@ -302,10 +303,10 @@ static Dwarf_Off MC_dwarf_attr_integrate_dieoffset(Dwarf_Die * die,
  *  \param dit the DIE
  *  \return DW_AT_type reference as a global offset in hexadecimal (or NULL)
  */
-static char *MC_dwarf_at_type(Dwarf_Die * die)
+static
+std::uint64_t MC_dwarf_at_type(Dwarf_Die * die)
 {
-  Dwarf_Off offset = MC_dwarf_attr_integrate_dieoffset(die, DW_AT_type);
-  return offset == 0 ? NULL : bprintf("%" PRIx64, offset);
+  return MC_dwarf_attr_integrate_dieoffset(die, DW_AT_type);
 }
 
 static uint64_t MC_dwarf_attr_integrate_addr(Dwarf_Die * die, int attribute)
@@ -449,7 +450,25 @@ static uint64_t MC_dwarf_array_element_count(Dwarf_Die * die, Dwarf_Die * unit)
   return result;
 }
 
-// ***** dw_type_t
+// ***** Variable
+
+/** Sort the variable by name and address.
+ *
+ *  We could use boost::container::flat_set instead.
+ */
+static bool MC_compare_variable(
+  simgrid::mc::Variable const& a, simgrid::mc::Variable const& b)
+{
+  int cmp = strcmp(a.name.c_str(), b.name.c_str());
+  if (cmp < 0)
+    return true;
+  else if (cmp > 0)
+    return false;
+  else
+    return a.address < b.address;
+}
+
+// ***** simgrid::mc::Type*
 
 /** \brief Initialize the location of a member of a type
  * (DW_AT_data_member_location of a DW_TAG_member).
@@ -458,7 +477,7 @@ static uint64_t MC_dwarf_array_element_count(Dwarf_Die * die, Dwarf_Die * unit)
  *  \param  member the member of the type
  *  \param  child  DIE of the member (DW_TAG_member)
  */
-static void MC_dwarf_fill_member_location(dw_type_t type, dw_type_t member,
+static void MC_dwarf_fill_member_location(simgrid::mc::Type* type, simgrid::mc::Type* member,
                                           Dwarf_Die * child)
 {
   if (dwarf_hasattr(child, DW_AT_data_bit_offset)) {
@@ -469,7 +488,8 @@ static void MC_dwarf_fill_member_location(dw_type_t type, dw_type_t member,
     if (type->type != DW_TAG_union_type) {
       xbt_die
           ("Missing DW_AT_data_member_location field in DW_TAG_member %s of type <%"
-           PRIx64 ">%s", member->name, (uint64_t) type->id, type->name);
+           PRIx64 ">%s", member->name.c_str(),
+           (uint64_t) type->id, type->name.c_str());
     } else {
       return;
     }
@@ -490,13 +510,9 @@ static void MC_dwarf_fill_member_location(dw_type_t type, dw_type_t member,
         xbt_die
             ("Could not read location expression DW_AT_data_member_location in DW_TAG_member %s of type <%"
              PRIx64 ">%s", MC_dwarf_attr_integrate_string(child, DW_AT_name),
-             (uint64_t) type->id, type->name);
-      }
-      if (len == 1 && expr[0].atom == DW_OP_plus_uconst) {
-        member->offset = expr[0].number;
-      } else {
-        mc_dwarf_expression_init(&member->location, len, expr);
+             (uint64_t) type->id, type->name.c_str());
       }
+      simgrid::mc::DwarfExpression(expr, expr+len);
       break;
     }
   case MC_DW_CLASS_CONSTANT:
@@ -504,11 +520,11 @@ static void MC_dwarf_fill_member_location(dw_type_t type, dw_type_t member,
     {
       Dwarf_Word offset;
       if (!dwarf_formudata(&attr, &offset))
-        member->offset = offset;
+        member->offset(offset);
       else
         xbt_die("Cannot get %s location <%" PRIx64 ">%s",
                 MC_dwarf_attr_integrate_string(child, DW_AT_name),
-                (uint64_t) type->id, type->name);
+                (uint64_t) type->id, type->name.c_str());
       break;
     }
   case MC_DW_CLASS_LOCLISTPTR:
@@ -524,11 +540,6 @@ static void MC_dwarf_fill_member_location(dw_type_t type, dw_type_t member,
 
 }
 
-static void dw_type_free_voidp(void *t)
-{
-  delete *(dw_type_t*)t;
-}
-
 /** \brief Populate the list of members of a type
  *
  *  \param info ELF object containing the type DIE
@@ -536,14 +547,12 @@ static void dw_type_free_voidp(void *t)
  *  \param unit DIE of the compilation unit containing the type DIE
  *  \param type the type
  */
-static void MC_dwarf_add_members(mc_object_info_t info, Dwarf_Die * die,
-                                 Dwarf_Die * unit, dw_type_t type)
+static void MC_dwarf_add_members(simgrid::mc::ObjectInformation* info, Dwarf_Die * die,
+                                 Dwarf_Die * unit, simgrid::mc::Type* type)
 {
   int res;
   Dwarf_Die child;
-  xbt_assert(!type->members);
-  type->members =
-      xbt_dynar_new(sizeof(dw_type_t), (void (*)(void *)) dw_type_free_voidp);
+  xbt_assert(type->members.empty());
   for (res = dwarf_child(die, &child); res == 0;
        res = dwarf_siblingof(&child, &child)) {
     int tag = dwarf_tag(&child);
@@ -558,38 +567,33 @@ static void MC_dwarf_add_members(mc_object_info_t info, Dwarf_Die * die,
         continue;
 
       // TODO, we should use another type (because is is not a type but a member)
-      dw_type_t member = xbt_new0(s_dw_type_t, 1);
-      member->type = tag;
+      simgrid::mc::Type member;
+      member.type = tag;
 
       // Global Offset:
-      member->id = dwarf_dieoffset(&child);
+      member.id = dwarf_dieoffset(&child);
 
       const char *name = MC_dwarf_attr_integrate_string(&child, DW_AT_name);
       if (name)
-        member->name = xbt_strdup(name);
-      else
-        member->name = NULL;
-
-      member->byte_size =
+        member.name = name;
+      member.byte_size =
           MC_dwarf_attr_integrate_uint(&child, DW_AT_byte_size, 0);
-      member->element_count = -1;
-      member->dw_type_id = MC_dwarf_at_type(&child);
-      member->members = NULL;
-      member->is_pointer_type = 0;
-      member->offset = 0;
+      member.element_count = -1;
+      member.type_id = MC_dwarf_at_type(&child);
 
       if (dwarf_hasattr(&child, DW_AT_data_bit_offset)) {
         xbt_die("Can't groke DW_AT_data_bit_offset.");
       }
 
-      MC_dwarf_fill_member_location(type, member, &child);
+      MC_dwarf_fill_member_location(type, &member, &child);
 
-      if (!member->dw_type_id) {
-        xbt_die("Missing type for member %s of <%" PRIx64 ">%s", member->name,
-                (uint64_t) type->id, type->name);
+      if (!member.type_id) {
+        xbt_die("Missing type for member %s of <%" PRIx64 ">%s",
+                member.name.c_str(),
+                (uint64_t) type->id, type->name.c_str());
       }
 
-      xbt_dynar_push(type->members, &member);
+      type->members.push_back(std::move(member));
     }
   }
 }
@@ -601,29 +605,24 @@ static void MC_dwarf_add_members(mc_object_info_t info, Dwarf_Die * die,
  *  \param unit compilation unit of the current DIE
  *  \return MC representation of the type
  */
-static dw_type_t MC_dwarf_die_to_type(mc_object_info_t info, Dwarf_Die * die,
-                                      Dwarf_Die * unit, dw_frame_t frame,
-                                      const char *ns)
+static simgrid::mc::Type MC_dwarf_die_to_type(
+  simgrid::mc::ObjectInformation* info, Dwarf_Die * die,
+  Dwarf_Die * unit, simgrid::mc::Frame* frame,
+  const char *ns)
 {
 
-  dw_type_t type = new s_dw_type();
-  type->type = -1;
-  type->id = 0;
-  type->name = NULL;
-  type->byte_size = 0;
-  type->element_count = -1;
-  type->dw_type_id = NULL;
-  type->members = NULL;
-  type->is_pointer_type = 0;
-  type->offset = 0;
+  simgrid::mc::Type type;
+  type.type = -1;
+  type.name = std::string();
+  type.element_count = -1;
 
-  type->type = dwarf_tag(die);
+  type.type = dwarf_tag(die);
 
   // Global Offset
-  type->id = dwarf_dieoffset(die);
+  type.id = dwarf_dieoffset(die);
 
   const char *prefix = "";
-  switch (type->type) {
+  switch (type.type) {
   case DW_TAG_structure_type:
     prefix = "struct ";
     break;
@@ -639,101 +638,99 @@ static dw_type_t MC_dwarf_die_to_type(mc_object_info_t info, Dwarf_Die * die,
 
   const char *name = MC_dwarf_attr_integrate_string(die, DW_AT_name);
   if (name != NULL) {
-    type->name =
-        ns ? bprintf("%s%s::%s", prefix, ns,
-                            name) : bprintf("%s%s", prefix, name);
+    char* full_name = ns ? bprintf("%s%s::%s", prefix, ns, name) :
+      bprintf("%s%s", prefix, name);
+    type.name = std::string(full_name);
+    free(full_name);
   }
 
-  type->dw_type_id = MC_dwarf_at_type(die);
+  type.type_id = MC_dwarf_at_type(die);
 
   // Some compilers do not emit DW_AT_byte_size for pointer_type,
   // so we fill this. We currently assume that the model-checked process is in
   // the same architecture..
-  if (type->type == DW_TAG_pointer_type)
-    type->byte_size = sizeof(void*);
+  if (type.type == DW_TAG_pointer_type)
+    type.byte_size = sizeof(void*);
 
   // Computation of the byte_size;
   if (dwarf_hasattr_integrate(die, DW_AT_byte_size))
-    type->byte_size = MC_dwarf_attr_integrate_uint(die, DW_AT_byte_size, 0);
-  else if (type->type == DW_TAG_array_type
-           || type->type == DW_TAG_structure_type
-           || type->type == DW_TAG_class_type) {
+    type.byte_size = MC_dwarf_attr_integrate_uint(die, DW_AT_byte_size, 0);
+  else if (type.type == DW_TAG_array_type
+           || type.type == DW_TAG_structure_type
+           || type.type == DW_TAG_class_type) {
     Dwarf_Word size;
     if (dwarf_aggregate_size(die, &size) == 0) {
-      type->byte_size = size;
+      type.byte_size = size;
     }
   }
 
-  switch (type->type) {
+  switch (type.type) {
   case DW_TAG_array_type:
-    type->element_count = MC_dwarf_array_element_count(die, unit);
+    type.element_count = MC_dwarf_array_element_count(die, unit);
     // TODO, handle DW_byte_stride and (not) DW_bit_stride
     break;
 
   case DW_TAG_pointer_type:
   case DW_TAG_reference_type:
   case DW_TAG_rvalue_reference_type:
-    type->is_pointer_type = 1;
+    type.is_pointer_type = 1;
     break;
 
   case DW_TAG_structure_type:
   case DW_TAG_union_type:
   case DW_TAG_class_type:
-    MC_dwarf_add_members(info, die, unit, type);
-    char *new_ns = ns == NULL ? xbt_strdup(type->name)
+    MC_dwarf_add_members(info, die, unit, &type);
+    char *new_ns = ns == NULL ? xbt_strdup(type.name.c_str())
         : bprintf("%s::%s", ns, name);
     MC_dwarf_handle_children(info, die, unit, frame, new_ns);
     free(new_ns);
     break;
   }
 
-  return type;
+  return std::move(type);
 }
 
-static void MC_dwarf_handle_type_die(mc_object_info_t info, Dwarf_Die * die,
-                                     Dwarf_Die * unit, dw_frame_t frame,
+static void MC_dwarf_handle_type_die(simgrid::mc::ObjectInformation* info, Dwarf_Die * die,
+                                     Dwarf_Die * unit, simgrid::mc::Frame* frame,
                                      const char *ns)
 {
-  dw_type_t type = MC_dwarf_die_to_type(info, die, unit, frame, ns);
-
-  char *key = bprintf("%" PRIx64, (uint64_t) type->id);
-  xbt_dict_set(info->types, key, type, NULL);
-  xbt_free(key);
-
-  if (type->name && type->byte_size != 0) {
-    xbt_dict_set(info->full_types_by_name, type->name, type, NULL);
-  }
+  simgrid::mc::Type type = MC_dwarf_die_to_type(info, die, unit, frame, ns);
+  auto& t = (info->types[type.id] = std::move(type));
+  if (!t.name.empty() && type.byte_size != 0)
+    info->full_types_by_name[t.name] = &t;
 }
 
 static int mc_anonymous_variable_index = 0;
 
-static dw_variable_t MC_die_to_variable(mc_object_info_t info, Dwarf_Die * die,
-                                        Dwarf_Die * unit, dw_frame_t frame,
-                                        const char *ns)
+static std::unique_ptr<simgrid::mc::Variable> MC_die_to_variable(
+  simgrid::mc::ObjectInformation* info, Dwarf_Die * die,
+  Dwarf_Die * unit, simgrid::mc::Frame* frame,
+  const char *ns)
 {
   // Skip declarations:
   if (MC_dwarf_attr_flag(die, DW_AT_declaration, false))
-    return NULL;
+    return nullptr;
 
   // Skip compile time constants:
   if (dwarf_hasattr(die, DW_AT_const_value))
-    return NULL;
+    return nullptr;
 
   Dwarf_Attribute attr_location;
   if (dwarf_attr(die, DW_AT_location, &attr_location) == NULL) {
     // No location: do not add it ?
-    return NULL;
+    return nullptr;
   }
 
-  dw_variable_t variable = xbt_new0(s_dw_variable_t, 1);
+  std::unique_ptr<simgrid::mc::Variable> variable =
+    std::unique_ptr<simgrid::mc::Variable>(new simgrid::mc::Variable());
   variable->dwarf_offset = dwarf_dieoffset(die);
   variable->global = frame == NULL;     // Can be override base on DW_AT_location
   variable->object_info = info;
 
   const char *name = MC_dwarf_attr_integrate_string(die, DW_AT_name);
-  variable->name = xbt_strdup(name);
-
-  variable->type_origin = MC_dwarf_at_type(die);
+  if (name)
+    variable->name = name;
+  variable->type_id = MC_dwarf_at_type(die);
 
   int form = dwarf_whatform(&attr_location);
   int klass =
@@ -747,19 +744,22 @@ static dw_variable_t MC_die_to_variable(mc_object_info_t info, Dwarf_Die * die,
       Dwarf_Op *expr;
       size_t len;
       if (dwarf_getlocation(&attr_location, &expr, &len)) {
-        xbt_die
-            ("Could not read location expression in DW_AT_location of variable <%"
-             PRIx64 ">%s", (uint64_t) variable->dwarf_offset, variable->name);
+        xbt_die(
+          "Could not read location expression in DW_AT_location "
+          "of variable <%" PRIx64 ">%s",
+          (uint64_t) variable->dwarf_offset,
+          variable->name.c_str());
       }
 
       if (len == 1 && expr[0].atom == DW_OP_addr) {
         variable->global = 1;
         uintptr_t offset = (uintptr_t) expr[0].number;
-        uintptr_t base = (uintptr_t) MC_object_base_address(info);
+        uintptr_t base = (uintptr_t) info->base_address();
         variable->address = (void *) (base + offset);
       } else {
-        mc_dwarf_location_list_init_from_expression(&variable->locations, len,
-                                                    expr);
+        simgrid::mc::LocationListEntry entry;
+        entry.expression = {expr, expr + len};
+        variable->location_list = { std::move(entry) };
       }
 
       break;
@@ -767,13 +767,16 @@ static dw_variable_t MC_die_to_variable(mc_object_info_t info, Dwarf_Die * die,
   case MC_DW_CLASS_LOCLISTPTR:
   case MC_DW_CLASS_CONSTANT:
     // Reference to location list:
-    mc_dwarf_location_list_init(&variable->locations, info, die,
-                                &attr_location);
+    mc_dwarf_location_list_init(
+      &variable->location_list, info, die,
+      &attr_location);
     break;
   default:
-    xbt_die("Unexpected form 0x%x (%i), class 0x%x (%i) list for location in <%"
-            PRIx64 ">%s", form, form, klass, klass,
-            (uint64_t) variable->dwarf_offset, variable->name);
+    xbt_die("Unexpected form 0x%x (%i), class 0x%x (%i) list for location "
+            "in <%" PRIx64 ">%s",
+            form, form, klass, klass,
+            (uint64_t) variable->dwarf_offset,
+            variable->name.c_str());
   }
 
   // Handle start_scope:
@@ -798,39 +801,38 @@ static dw_variable_t MC_die_to_variable(mc_object_info_t info, Dwarf_Die * die,
     }
   }
 
-  if (ns && variable->global) {
-    char *old_name = variable->name;
-    variable->name = bprintf("%s::%s", ns, old_name);
-    free(old_name);
-  }
+  if (ns && variable->global)
+    variable->name =
+      std::string(ns) + "::" + variable->name;
+
   // The current code needs a variable name,
   // generate a fake one:
-  if (!variable->name) {
-    variable->name = bprintf("@anonymous#%i", mc_anonymous_variable_index++);
-  }
+  if (variable->name.empty())
+    variable->name =
+      "@anonymous#" + std::to_string(mc_anonymous_variable_index++);
 
-  return variable;
+  return std::move(variable);
 }
 
-static void MC_dwarf_handle_variable_die(mc_object_info_t info, Dwarf_Die * die,
-                                         Dwarf_Die * unit, dw_frame_t frame,
+static void MC_dwarf_handle_variable_die(simgrid::mc::ObjectInformation* info, Dwarf_Die * die,
+                                         Dwarf_Die * unit, simgrid::mc::Frame* frame,
                                          const char *ns)
 {
-  dw_variable_t variable =
-      MC_die_to_variable(info, die, unit, frame, ns);
-  if (variable == NULL)
+  std::unique_ptr<simgrid::mc::Variable> variable =
+    MC_die_to_variable(info, die, unit, frame, ns);
+  if (!variable)
     return;
-  MC_dwarf_register_variable(info, frame, variable);
-}
-
-static void mc_frame_free_voipd(dw_frame_t * p)
-{
-  mc_frame_free(*p);
-  *p = NULL;
+  // Those arrays are sorted later:
+  else if (variable->global)
+    info->global_variables.push_back(std::move(*variable));
+  else if (frame != nullptr)
+    frame->variables.push_back(std::move(*variable));
+  else
+    xbt_die("No frame for this local variable");
 }
 
-static void MC_dwarf_handle_scope_die(mc_object_info_t info, Dwarf_Die * die,
-                                      Dwarf_Die * unit, dw_frame_t parent_frame,
+static void MC_dwarf_handle_scope_die(simgrid::mc::ObjectInformation* info, Dwarf_Die * die,
+                                      Dwarf_Die * unit, simgrid::mc::Frame* parent_frame,
                                       const char *ns)
 {
   // TODO, handle DW_TAG_type/DW_TAG_location for DW_TAG_with_stmt
@@ -845,33 +847,33 @@ static void MC_dwarf_handle_scope_die(mc_object_info_t info, Dwarf_Die * die,
   if (klass == mc_tag_scope)
     xbt_assert(parent_frame, "No parent scope for this scope");
 
-  dw_frame_t frame = xbt_new0(s_dw_frame_t, 1);
+  simgrid::mc::Frame frame;
 
-  frame->tag = tag;
-  frame->id = dwarf_dieoffset(die);
-  frame->object_info = info;
+  frame.tag = tag;
+  frame.id = dwarf_dieoffset(die);
+  frame.object_info = info;
 
   if (klass == mc_tag_subprogram) {
     const char *name = MC_dwarf_attr_integrate_string(die, DW_AT_name);
-    frame->name =
-        ns ? bprintf("%s::%s", ns, name) : xbt_strdup(name);
+    if(ns)
+      frame.name  = std::string(ns) + "::" + name;
+    else if (name)
+      frame.name = name;
+    else
+      frame.name.clear();
   }
 
-  frame->abstract_origin_id =
-      MC_dwarf_attr_dieoffset(die, DW_AT_abstract_origin);
+  frame.abstract_origin_id =
+    MC_dwarf_attr_dieoffset(die, DW_AT_abstract_origin);
 
   // This is the base address for DWARF addresses.
   // Relocated addresses are offset from this base address.
   // See DWARF4 spec 7.5
-  void *base = MC_object_base_address(info);
-
-  // Variables are filled in the (recursive) call of MC_dwarf_handle_children:
-  frame->variables =
-      xbt_dynar_new(sizeof(dw_variable_t), dw_variable_free_voidp);
+  void *base = info->base_address();
 
   // TODO, support DW_AT_ranges
   uint64_t low_pc = MC_dwarf_attr_integrate_addr(die, DW_AT_low_pc);
-  frame->low_pc = low_pc ? ((char *) base) + low_pc : 0;
+  frame.low_pc = low_pc ? ((char *) base) + low_pc : 0;
   if (low_pc) {
     // DW_AT_high_pc:
     Dwarf_Attribute attr;
@@ -889,14 +891,14 @@ static void MC_dwarf_handle_scope_die(mc_object_info_t info, Dwarf_Die * die,
 
       if (dwarf_formsdata(&attr, &offset) != 0)
         xbt_die("Could not read constant");
-      frame->high_pc = (void *) ((char *) frame->low_pc + offset);
+      frame.high_pc = (void *) ((char *) frame.low_pc + offset);
       break;
 
       // DW_AT_high_pc is a relocatable address:
     case MC_DW_CLASS_ADDRESS:
       if (dwarf_formaddr(&attr, &high_pc) != 0)
         xbt_die("Could not read address");
-      frame->high_pc = ((char *) base) + high_pc;
+      frame.high_pc = ((char *) base) + high_pc;
       break;
 
     default:
@@ -908,28 +910,27 @@ static void MC_dwarf_handle_scope_die(mc_object_info_t info, Dwarf_Die * die,
   if (klass == mc_tag_subprogram) {
     Dwarf_Attribute attr_frame_base;
     if (dwarf_attr_integrate(die, DW_AT_frame_base, &attr_frame_base))
-      mc_dwarf_location_list_init(&frame->frame_base, info, die,
+      mc_dwarf_location_list_init(&frame.frame_base, info, die,
                                   &attr_frame_base);
   }
 
-  frame->scopes =
-      xbt_dynar_new(sizeof(dw_frame_t), (void_f_pvoid_t) mc_frame_free_voipd);
+  // Handle children:
+  MC_dwarf_handle_children(info, die, unit, &frame, ns);
+
+  // Someone needs this to be sorted but who?
+  std::sort(frame.variables.begin(), frame.variables.end(),
+    MC_compare_variable);
 
   // Register it:
-  if (klass == mc_tag_subprogram) {
-    char *key = bprintf("%" PRIx64, (uint64_t) frame->id);
-    xbt_dict_set(info->subprograms, key, frame, NULL);
-    xbt_free(key);
-  } else if (klass == mc_tag_scope) {
-    xbt_dynar_push(parent_frame->scopes, &frame);
-  }
-  // Handle children:
-  MC_dwarf_handle_children(info, die, unit, frame, ns);
+  if (klass == mc_tag_subprogram)
+    info->subprograms[frame.id] = frame;
+  else if (klass == mc_tag_scope)
+    parent_frame->scopes.push_back(std::move(frame));
 }
 
-static void mc_dwarf_handle_namespace_die(mc_object_info_t info,
+static void mc_dwarf_handle_namespace_die(simgrid::mc::ObjectInformation* info,
                                           Dwarf_Die * die, Dwarf_Die * unit,
-                                          dw_frame_t frame,
+                                          simgrid::mc::Frame* frame,
                                           const char *ns)
 {
   const char *name = MC_dwarf_attr_integrate_string(die, DW_AT_name);
@@ -941,8 +942,8 @@ static void mc_dwarf_handle_namespace_die(mc_object_info_t info,
   xbt_free(new_ns);
 }
 
-static void MC_dwarf_handle_children(mc_object_info_t info, Dwarf_Die * die,
-                                     Dwarf_Die * unit, dw_frame_t frame,
+static void MC_dwarf_handle_children(simgrid::mc::ObjectInformation* info, Dwarf_Die * die,
+                                     Dwarf_Die * unit, simgrid::mc::Frame* frame,
                                      const char *ns)
 {
   // For each child DIE:
@@ -954,8 +955,8 @@ static void MC_dwarf_handle_children(mc_object_info_t info, Dwarf_Die * die,
   }
 }
 
-static void MC_dwarf_handle_die(mc_object_info_t info, Dwarf_Die * die,
-                                Dwarf_Die * unit, dw_frame_t frame,
+static void MC_dwarf_handle_die(simgrid::mc::ObjectInformation* info, Dwarf_Die * die,
+                                Dwarf_Die * unit, simgrid::mc::Frame* frame,
                                 const char *ns)
 {
   int tag = dwarf_tag(die);
@@ -993,16 +994,15 @@ static void MC_dwarf_handle_die(mc_object_info_t info, Dwarf_Die * die,
  *  Read the DWARf information of the EFFL object and populate the
  *  lists of types, variables, functions.
  */
-void MC_dwarf_get_variables(mc_object_info_t info)
+void MC_dwarf_get_variables(simgrid::mc::ObjectInformation* info)
 {
-  int fd = open(info->file_name, O_RDONLY);
-  if (fd < 0) {
-    xbt_die("Could not open file %s", info->file_name);
-  }
+  int fd = open(info->file_name.c_str(), O_RDONLY);
+  if (fd < 0)
+    xbt_die("Could not open file %s", info->file_name.c_str());
   Dwarf *dwarf = dwarf_begin(fd, DWARF_C_READ);
-  if (dwarf == NULL) {
-    xbt_die("Your program must be compiled with -g (%s)", info->file_name);
-  }
+  if (dwarf == NULL)
+    xbt_die("Your program must be compiled with -g (%s)",
+      info->file_name.c_str());
   // For each compilation unit:
   Dwarf_Off offset = 0;
   Dwarf_Off next_offset = 0;
@@ -1028,113 +1028,10 @@ void MC_dwarf_get_variables(mc_object_info_t info)
   close(fd);
 }
 
-/************************** Free functions *************************/
-
-void mc_frame_free(dw_frame_t frame)
-{
-  xbt_free(frame->name);
-  mc_dwarf_location_list_clear(&(frame->frame_base));
-  xbt_dynar_free(&(frame->variables));
-  xbt_dynar_free(&(frame->scopes));
-  xbt_free(frame);
-}
-
-s_dw_type::s_dw_type()
-{
-  this->type = 0;
-  this->id = 0;
-  this->name = nullptr;
-  this->byte_size = 0;
-  this->element_count = 0;
-  this->dw_type_id = nullptr;
-  this->members = nullptr;
-  this->is_pointer_type = 0;
-  this->location = { 0, 0, 0, 0};
-  this->offset = 0;
-  this->subtype = nullptr;
-  this->full_type = nullptr;
-}
-
-s_dw_type::~s_dw_type()
-{
-  xbt_free(this->name);
-  xbt_free(this->dw_type_id);
-  xbt_dynar_free(&this->members);
-  mc_dwarf_expression_clear(&this->location);
-}
-
-static void dw_type_free(dw_type_t t)
-{
-  delete t;
-}
-
-void dw_variable_free(dw_variable_t v)
-{
-  if (v) {
-    xbt_free(v->name);
-    xbt_free(v->type_origin);
-
-    if (v->locations.locations)
-      mc_dwarf_location_list_clear(&v->locations);
-    xbt_free(v);
-  }
-}
-
-void dw_variable_free_voidp(void *t)
-{
-  dw_variable_free((dw_variable_t) * (void **) t);
-}
-
-// ***** object_info
-
-s_mc_object_info::s_mc_object_info()
-{
-  this->flags = 0;
-  this->file_name = nullptr;
-  this->start = nullptr;
-  this->end = nullptr;
-  this->start_exec = nullptr;
-  this->end_exec = nullptr;
-  this->start_rw = nullptr;
-  this->end_rw = nullptr;
-  this->start_ro = nullptr;
-  this->end_ro = nullptr;
-  this->subprograms = xbt_dict_new_homogeneous((void (*)(void *)) mc_frame_free);
-  this->global_variables =
-      xbt_dynar_new(sizeof(dw_variable_t), dw_variable_free_voidp);
-  this->types = xbt_dict_new_homogeneous((void (*)(void *)) dw_type_free);
-  this->full_types_by_name = xbt_dict_new_homogeneous(NULL);
-  this->functions_index = nullptr;
-}
-
-s_mc_object_info::~s_mc_object_info()
-{
-  xbt_free(this->file_name);
-  xbt_dict_free(&this->subprograms);
-  xbt_dynar_free(&this->global_variables);
-  xbt_dict_free(&this->types);
-  xbt_dict_free(&this->full_types_by_name);
-  xbt_dynar_free(&this->functions_index);
-}
-
-// ***** Helpers
-
-void *MC_object_base_address(mc_object_info_t info)
-{
-  if (info->flags & MC_OBJECT_INFO_EXECUTABLE)
-    return 0;
-  void *result = info->start_exec;
-  if (info->start_rw != NULL && result > (void *) info->start_rw)
-    result = info->start_rw;
-  if (info->start_ro != NULL && result > (void *) info->start_ro)
-    result = info->start_ro;
-  return result;
-}
-
 // ***** Functions index
 
-static int MC_compare_frame_index_items(mc_function_index_item_t a,
-                                        mc_function_index_item_t b)
+static int MC_compare_frame_index_items(simgrid::mc::FunctionIndexEntry* a,
+                                        simgrid::mc::FunctionIndexEntry* b)
 {
   if (a->low_pc < b->low_pc)
     return -1;
@@ -1144,239 +1041,126 @@ static int MC_compare_frame_index_items(mc_function_index_item_t a,
     return 1;
 }
 
-static void MC_make_functions_index(mc_object_info_t info)
+static void MC_make_functions_index(simgrid::mc::ObjectInformation* info)
 {
-  xbt_dynar_t index = xbt_dynar_new(sizeof(s_mc_function_index_item_t), NULL);
-
-  // Populate the array:
-  dw_frame_t frame = NULL;
-  xbt_dict_cursor_t cursor;
-  char *key;
-  xbt_dict_foreach(info->subprograms, cursor, key, frame) {
-    if (frame->low_pc == NULL)
+  info->functions_index.clear();
+
+  for (auto& e : info->subprograms) {
+    if (e.second.low_pc == nullptr)
       continue;
-    s_mc_function_index_item_t entry;
-    entry.low_pc = frame->low_pc;
-    entry.high_pc = frame->high_pc;
-    entry.function = frame;
-    xbt_dynar_push(index, &entry);
+    simgrid::mc::FunctionIndexEntry entry;
+    entry.low_pc = e.second.low_pc;
+    entry.function = &e.second;
+    info->functions_index.push_back(entry);
   }
 
-  mc_function_index_item_t base =
-      (mc_function_index_item_t) xbt_dynar_get_ptr(index, 0);
+  info->functions_index.shrink_to_fit();
 
   // Sort the array by low_pc:
-  qsort(base,
-        xbt_dynar_length(index),
-        sizeof(s_mc_function_index_item_t),
-        (int (*)(const void *, const void *)) MC_compare_frame_index_items);
-
-  info->functions_index = index;
+  std::sort(info->functions_index.begin(), info->functions_index.end(),
+        [](simgrid::mc::FunctionIndexEntry& a,
+          simgrid::mc::FunctionIndexEntry& b)
+        {
+          return a.low_pc < b.low_pc;
+        });
 }
 
-static void MC_post_process_variables(mc_object_info_t info)
+static void MC_post_process_variables(simgrid::mc::ObjectInformation* info)
 {
-  unsigned cursor = 0;
-  dw_variable_t variable = NULL;
-  xbt_dynar_foreach(info->global_variables, cursor, variable) {
-    if (variable->type_origin) {
-      variable->type = (dw_type_t) xbt_dict_get_or_null(info->types, variable->type_origin);
+  // Someone needs this to be sorted but who?
+  std::sort(info->global_variables.begin(), info->global_variables.end(),
+    MC_compare_variable);
+
+  for(simgrid::mc::Variable& variable : info->global_variables)
+    if (variable.type_id) {
+      variable.type = simgrid::util::find_map_ptr(
+        info->types, variable.type_id);
     }
-  }
 }
 
-static void mc_post_process_scope(mc_object_info_t info, dw_frame_t scope)
+static void mc_post_process_scope(simgrid::mc::ObjectInformation* info, simgrid::mc::Frame* scope)
 {
 
   if (scope->tag == DW_TAG_inlined_subroutine) {
-
     // Attach correct namespaced name in inlined subroutine:
-    char *key = bprintf("%" PRIx64, (uint64_t) scope->abstract_origin_id);
-    dw_frame_t abstract_origin = (dw_frame_t) xbt_dict_get_or_null(info->subprograms, key);
-    xbt_assert(abstract_origin, "Could not lookup abstract origin %s", key);
-    xbt_free(key);
-    scope->name = xbt_strdup(abstract_origin->name);
-
+    auto i = info->subprograms.find(scope->abstract_origin_id);
+    xbt_assert(i != info->subprograms.end(),
+      "Could not lookup abstract origin %" PRIx64,
+      (uint64_t) scope->abstract_origin_id);
+    scope->name = i->second.name;
   }
+
   // Direct:
-  unsigned cursor = 0;
-  dw_variable_t variable = NULL;
-  xbt_dynar_foreach(scope->variables, cursor, variable) {
-    if (variable->type_origin) {
-      variable->type = (dw_type_t) xbt_dict_get_or_null(info->types, variable->type_origin);
+  for (simgrid::mc::Variable& variable : scope->variables)
+    if (variable.type_id) {
+      variable.type = simgrid::util::find_map_ptr(
+        info->types, variable.type_id);
     }
-  }
 
   // Recursive post-processing of nested-scopes:
-  dw_frame_t nested_scope = NULL;
-  xbt_dynar_foreach(scope->scopes, cursor, nested_scope)
-      mc_post_process_scope(info, nested_scope);
+  for (simgrid::mc::Frame& nested_scope : scope->scopes)
+      mc_post_process_scope(info, &nested_scope);
 
 }
 
-static void MC_post_process_functions(mc_object_info_t info)
-{
-  xbt_dict_cursor_t cursor;
-  char *key;
-  dw_frame_t subprogram = NULL;
-  xbt_dict_foreach(info->subprograms, cursor, key, subprogram) {
-    mc_post_process_scope(info, subprogram);
-  }
-}
-
-
 /** \brief Fill/lookup the "subtype" field.
  */
-static void MC_resolve_subtype(mc_object_info_t info, dw_type_t type)
+static void MC_resolve_subtype(simgrid::mc::ObjectInformation* info, simgrid::mc::Type* type)
 {
-
-  if (type->dw_type_id == NULL)
+  if (!type->type_id)
     return;
-  type->subtype = (dw_type_t) xbt_dict_get_or_null(info->types, type->dw_type_id);
-  if (type->subtype == NULL)
+  type->subtype = simgrid::util::find_map_ptr(info->types, type->type_id);
+  if (type->subtype == nullptr)
     return;
   if (type->subtype->byte_size != 0)
     return;
-  if (type->subtype->name == NULL)
+  if (type->subtype->name.empty())
     return;
   // Try to find a more complete description of the type:
   // We need to fix in order to support C++.
-
-  dw_type_t subtype =
-    (dw_type_t) xbt_dict_get_or_null(info->full_types_by_name, type->subtype->name);
-  if (subtype != NULL) {
-    type->subtype = subtype;
-  }
-
+  simgrid::mc::Type** subtype = simgrid::util::find_map_ptr(
+    info->full_types_by_name, type->subtype->name);
+  if (subtype)
+    type->subtype = *subtype;
 }
 
-static void MC_post_process_types(mc_object_info_t info)
+static void MC_post_process_types(simgrid::mc::ObjectInformation* info)
 {
-  xbt_dict_cursor_t cursor = NULL;
-  char *origin;
-  dw_type_t type;
-
   // Lookup "subtype" field:
-  xbt_dict_foreach(info->types, cursor, origin, type) {
-    MC_resolve_subtype(info, type);
-
-    dw_type_t member;
-    unsigned int i = 0;
-    if (type->members != NULL)
-      xbt_dynar_foreach(type->members, i, member) {
-      MC_resolve_subtype(info, member);
-      }
+  for(auto& i : info->types) {
+    MC_resolve_subtype(info, &(i.second));
+    for (simgrid::mc::Type& member : i.second.members)
+      MC_resolve_subtype(info, &member);
   }
 }
 
 /** \brief Finds informations about a given shared object/executable */
-std::shared_ptr<s_mc_object_info_t> MC_find_object_info(
+std::shared_ptr<simgrid::mc::ObjectInformation> MC_find_object_info(
   std::vector<simgrid::mc::VmMap> const& maps, const char *name, int executable)
 {
-  std::shared_ptr<s_mc_object_info_t> result =
-    std::make_shared<s_mc_object_info_t>();
+  std::shared_ptr<simgrid::mc::ObjectInformation> result =
+    std::make_shared<simgrid::mc::ObjectInformation>();
   if (executable)
     result->flags |= MC_OBJECT_INFO_EXECUTABLE;
-  result->file_name = xbt_strdup(name);
+  result->file_name = name;
   MC_find_object_address(maps, result.get());
   MC_dwarf_get_variables(result.get());
-  MC_post_process_types(result.get());
   MC_post_process_variables(result.get());
-  MC_post_process_functions(result.get());
+  MC_post_process_types(result.get());
+  for (auto& entry : result.get()->subprograms)
+    mc_post_process_scope(result.get(), &entry.second);
   MC_make_functions_index(result.get());
   return std::move(result);
 }
 
 /*************************************************************************/
 
-static int MC_dwarf_get_variable_index(xbt_dynar_t variables, char *var,
-                                       void *address)
-{
-
-  if (xbt_dynar_is_empty(variables))
-    return 0;
-
-  unsigned int cursor = 0;
-  int start = 0;
-  int end = xbt_dynar_length(variables) - 1;
-  dw_variable_t var_test = NULL;
-
-  while (start <= end) {
-    cursor = (start + end) / 2;
-    var_test =
-        (dw_variable_t) xbt_dynar_get_as(variables, cursor, dw_variable_t);
-    if (strcmp(var_test->name, var) < 0) {
-      start = cursor + 1;
-    } else if (strcmp(var_test->name, var) > 0) {
-      end = cursor - 1;
-    } else {
-      if (address) {            /* global variable */
-        if (var_test->address == address)
-          return -1;
-        if (var_test->address > address)
-          end = cursor - 1;
-        else
-          start = cursor + 1;
-      } else {                  /* local variable */
-        return -1;
-      }
-    }
-  }
-
-  if (strcmp(var_test->name, var) == 0) {
-    if (address && var_test->address < address)
-      return cursor + 1;
-    else
-      return cursor;
-  } else if (strcmp(var_test->name, var) < 0)
-    return cursor + 1;
-  else
-    return cursor;
-
-}
-
-void MC_dwarf_register_global_variable(mc_object_info_t info,
-                                       dw_variable_t variable)
-{
-  int index =
-      MC_dwarf_get_variable_index(info->global_variables, variable->name,
-                                  variable->address);
-  if (index != -1)
-    xbt_dynar_insert_at(info->global_variables, index, &variable);
-  // TODO, else ?
-}
-
-void MC_dwarf_register_non_global_variable(mc_object_info_t info,
-                                           dw_frame_t frame,
-                                           dw_variable_t variable)
-{
-  xbt_assert(frame, "Frame is NULL");
-  int index =
-      MC_dwarf_get_variable_index(frame->variables, variable->name, NULL);
-  if (index != -1)
-    xbt_dynar_insert_at(frame->variables, index, &variable);
-  // TODO, else ?
-}
-
-void MC_dwarf_register_variable(mc_object_info_t info, dw_frame_t frame,
-                                dw_variable_t variable)
-{
-  if (variable->global)
-    MC_dwarf_register_global_variable(info, variable);
-  else if (frame == NULL)
-    xbt_die("No frame for this local variable");
-  else
-    MC_dwarf_register_non_global_variable(info, frame, variable);
-}
-
-void MC_post_process_object_info(mc_process_t process, mc_object_info_t info)
+void MC_post_process_object_info(simgrid::mc::Process* process, simgrid::mc::ObjectInformation* info)
 {
-  xbt_dict_cursor_t cursor = NULL;
-  char *key = NULL;
-  dw_type_t type = NULL;
-  xbt_dict_foreach(info->types, cursor, key, type) {
+  for (auto& i : info->types) {
 
-    dw_type_t subtype = type;
+    simgrid::mc::Type* type = &(i.second);
+    simgrid::mc::Type* subtype = type;
     while (subtype->type == DW_TAG_typedef || subtype->type == DW_TAG_volatile_type
       || subtype->type == DW_TAG_const_type) {
       if (subtype->subtype)
@@ -1386,13 +1170,12 @@ void MC_post_process_object_info(mc_process_t process, mc_object_info_t info)
     }
 
     // Resolve full_type:
-    if (subtype->name && subtype->byte_size == 0) {
+    if (!subtype->name.empty() && subtype->byte_size == 0) {
       for (auto const& object_info : process->object_infos) {
-        dw_type_t same_type = (dw_type_t)
-            xbt_dict_get_or_null(object_info->full_types_by_name,
-                                 subtype->name);
-        if (same_type && same_type->name && same_type->byte_size) {
-          type->full_type = same_type;
+        auto i = object_info->full_types_by_name.find(subtype->name);
+        if (i != object_info->full_types_by_name.end()
+            && !i->second->name.empty() && i->second->byte_size) {
+          type->full_type = i->second;
           break;
         }
       }
index 33a01b9..cc4b930 100644 (file)
@@ -230,7 +230,7 @@ int mc_dwarf_execute_expression(size_t n, const Dwarf_Op * ops,
       if (state->stack_size == MC_EXPRESSION_STACK_SIZE)
         return MC_EXPRESSION_E_STACK_OVERFLOW;
       Dwarf_Off addr = (Dwarf_Off) (uintptr_t)
-        MC_object_base_address(state->object_info) + op->number;
+        state->object_info->base_address() + op->number;
       error = mc_dwarf_push_value(state, addr);
       break;
     }
@@ -429,11 +429,11 @@ int mc_dwarf_execute_expression(size_t n, const Dwarf_Op * ops,
  *  \deprecated Use mc_dwarf_resolve_expression
  */
 void mc_dwarf_resolve_location(mc_location_t location,
-                               mc_expression_t expression,
-                               mc_object_info_t object_info,
+                               simgrid::mc::DwarfExpression* expression,
+                               simgrid::mc::ObjectInformation* object_info,
                                unw_cursor_t * c,
                                void *frame_pointer_address,
-                               mc_address_space_t address_space, int process_index)
+                               simgrid::mc::AddressSpace* address_space, int process_index)
 {
   s_mc_expression_state_t state;
   memset(&state, 0, sizeof(s_mc_expression_state_t));
@@ -443,10 +443,12 @@ void mc_dwarf_resolve_location(mc_location_t location,
   state.object_info = object_info;
   state.process_index = process_index;
 
-  if (expression->size >= 1
-    && expression->ops[0].atom >=DW_OP_reg0 && expression->ops[0].atom <= DW_OP_reg31) {
-    int dwarf_register = expression->ops[0].atom - DW_OP_reg0;
-    xbt_assert(c, "Missing frame context for register operation DW_OP_reg%i",
+  if (expression->size() >= 1
+      && (*expression)[0].atom >=DW_OP_reg0
+      && (*expression)[0].atom <= DW_OP_reg31) {
+    int dwarf_register = (*expression)[0].atom - DW_OP_reg0;
+    xbt_assert(c,
+      "Missing frame context for register operation DW_OP_reg%i",
       dwarf_register);
     location->memory_location = NULL;
     location->cursor = c;
@@ -454,7 +456,8 @@ void mc_dwarf_resolve_location(mc_location_t location,
     return;
   }
 
-  if (mc_dwarf_execute_expression(expression->size, expression->ops, &state))
+  if (mc_dwarf_execute_expression(
+      expression->size(), expression->data(), &state))
     xbt_die("Error evaluating DWARF expression");
   if (state.stack_size == 0)
     xbt_die("No value on the stack");
@@ -465,24 +468,23 @@ void mc_dwarf_resolve_location(mc_location_t location,
   }
 }
 
-static mc_expression_t mc_find_expression(mc_location_list_t locations, unw_word_t ip) {
-  for (size_t i = 0; i != locations->size; ++i) {
-    mc_expression_t expression = locations->locations + i;
-    if ((expression->lowpc == NULL && expression->highpc == NULL)
-        || (ip && ip >= (unw_word_t) expression->lowpc
-            && ip < (unw_word_t) expression->highpc)) {
-      return expression;
-    }
-  }
-  return NULL;
+// TODO, move this in a method of LocationList
+static simgrid::mc::DwarfExpression* mc_find_expression(
+    simgrid::mc::LocationList* locations, unw_word_t ip)
+{
+  for (simgrid::mc::LocationListEntry& entry : *locations)
+    if (entry.valid_for_ip(ip))
+      return &entry.expression;
+  return nullptr;
 }
 
 void mc_dwarf_resolve_locations(mc_location_t location,
-                                     mc_location_list_t locations,
-                                     mc_object_info_t object_info,
-                                     unw_cursor_t * c,
-                                     void *frame_pointer_address,
-                                     mc_address_space_t address_space, int process_index)
+                                simgrid::mc::LocationList* locations,
+                                simgrid::mc::ObjectInformation* object_info,
+                                unw_cursor_t * c,
+                                void *frame_pointer_address,
+                                simgrid::mc::AddressSpace* address_space,
+                                int process_index)
 {
 
   unw_word_t ip = 0;
@@ -491,7 +493,7 @@ void mc_dwarf_resolve_locations(mc_location_t location,
       xbt_die("Could not resolve IP");
   }
 
-  mc_expression_t expression = mc_find_expression(locations, ip);
+  simgrid::mc::DwarfExpression* expression = mc_find_expression(locations, ip);
   if (expression) {
     mc_dwarf_resolve_location(location,
                               expression, object_info, c,
@@ -506,7 +508,7 @@ void mc_dwarf_resolve_locations(mc_location_t location,
  *  \param frame
  *  \param unw_cursor
  */
-void *mc_find_frame_base(dw_frame_t frame, mc_object_info_t object_info,
+void *mc_find_frame_base(simgrid::mc::Frame* frame, simgrid::mc::ObjectInformation* object_info,
                          unw_cursor_t * unw_cursor)
 {
   s_mc_location_t location;
@@ -534,50 +536,11 @@ void *mc_find_frame_base(dw_frame_t frame, mc_object_info_t object_info,
   }
 }
 
-void mc_dwarf_expression_clear(mc_expression_t expression)
-{
-  free(expression->ops);
-  expression->ops = NULL;
-  expression->size = 0;
-  expression->lowpc = NULL;
-  expression->highpc = NULL;
-}
-
-void mc_dwarf_location_list_clear(mc_location_list_t list)
+void mc_dwarf_location_list_init(
+  simgrid::mc::LocationList* list, simgrid::mc::ObjectInformation* info,
+  Dwarf_Die * die, Dwarf_Attribute * attr)
 {
-  for (size_t i = 0; i != list->size; ++i) {
-    mc_dwarf_expression_clear(list->locations + i);
-  }
-  free(list->locations);
-  list->locations = NULL;
-  list->size = 0;
-}
-
-void mc_dwarf_expression_init(mc_expression_t expression, size_t len,
-                              Dwarf_Op * ops)
-{
-  expression->lowpc = NULL;
-  expression->highpc = NULL;
-  expression->size = len;
-  expression->ops = (Dwarf_Op*) xbt_malloc(len * sizeof(Dwarf_Op));
-  memcpy(expression->ops, ops, len * sizeof(Dwarf_Op));
-}
-
-void mc_dwarf_location_list_init_from_expression(mc_location_list_t target,
-                                                 size_t len, Dwarf_Op * ops)
-{
-  target->size = 1;
-  target->locations = (mc_expression_t) xbt_malloc(sizeof(s_mc_expression_t));
-  mc_dwarf_expression_init(target->locations, len, ops);
-}
-
-void mc_dwarf_location_list_init(mc_location_list_t list, mc_object_info_t info,
-                                 Dwarf_Die * die, Dwarf_Attribute * attr)
-{
-  if (list->locations) {
-    mc_dwarf_location_list_clear(list);
-  }
-  list->size = 0;
+  list->clear();
 
   ptrdiff_t offset = 0;
   Dwarf_Addr base, start, end;
@@ -592,21 +555,15 @@ void mc_dwarf_location_list_init(mc_location_list_t list, mc_object_info_t info,
     else if (offset == -1)
       xbt_die("Error while loading location list");
 
-    int i = list->size;
-    list->size++;
-    list->locations =
-        (mc_expression_t) realloc(list->locations,
-                                  list->size * sizeof(s_mc_expression_t));
-    mc_expression_t expression = list->locations + i;
-    expression->ops = NULL;
-    mc_dwarf_expression_init(expression, len, ops);
-
-    void *base =
-        info->
-        flags & MC_OBJECT_INFO_EXECUTABLE ? 0 : MC_object_base_address(info);
+    simgrid::mc::LocationListEntry entry;
+    entry.expression = simgrid::mc::DwarfExpression(ops, ops + len);
+
+    void *base = info->base_address();
     // If start == 0, this is not a location list:
-    expression->lowpc = start == 0 ? NULL : (char *) base + start;
-    expression->highpc = start == 0 ? NULL : (char *) base + end;
+    entry.lowpc = start == 0 ? NULL : (char *) base + start;
+    entry.highpc = start == 0 ? NULL : (char *) base + end;
+
+    list->push_back(std::move(entry));
   }
 
 }
index a247eba..a3a56e6 100644 (file)
@@ -4,59 +4,27 @@
 /* This program is free software; you can redistribute it and/or modify it
  * under the terms of the license (GNU LGPL) which comes with this package. */
 
+/** \file mc_forward.h
+ *
+ *  Define type names for pointers of MC objects for the C code
+ */
+
 #ifndef SIMGRID_MC_FORWARD_H
 #define SIMGRID_MC_FORWARD_H
 
-#include <xbt/misc.h>
-#include <mc/datatypes.h>
-
 #ifdef __cplusplus
 
-#define MC_OVERRIDE
-
-namespace simgrid {
-namespace mc {
-
-class PageStore;
-class ModelChecker;
-class AddressSpace;
-class Process;
-class Snapshot;
-
-}
-}
-
-typedef ::simgrid::mc::ModelChecker s_mc_model_checker_t;
-typedef ::simgrid::mc::PageStore s_mc_pages_store_t;
-typedef ::simgrid::mc::AddressSpace s_mc_address_space_t;
-typedef ::simgrid::mc::Process s_mc_process_t;
-typedef ::simgrid::mc::Snapshot s_mc_snapshot_t;
+// If we're in C++, we give the real definition:
+#include "mc_forward.hpp"
+typedef simgrid::mc::Snapshot *mc_snapshot_t;
+typedef simgrid::mc::Type *mc_type_t;
 
 #else
 
-typedef struct _s_mc_model_checker s_mc_model_checker_t;
-typedef struct _s_mc_pages_store s_mc_pages_store_t;
-typedef struct _s_mc_address_space_t s_mc_address_space_t;
-typedef struct _s_mc_process_t s_mc_process_t;
-typedef struct _s_mc_snapshot_t s_mc_snapshot_t;
+// Otherwise we use dummy opaque structs:
+typedef struct _mc_snapshot_t *mc_snapshot_t;
+typedef struct _s_mc_type_t *mc_type_t;
 
 #endif
 
-typedef struct s_mc_object_info s_mc_object_info_t, *mc_object_info_t;
-typedef struct s_dw_type s_dw_type_t, *dw_type_t;
-typedef struct s_memory_map s_memory_map_t, *memory_map_t;
-typedef struct s_dw_variable s_dw_variable_t, *dw_variable_t;
-typedef struct s_dw_frame s_dw_frame_t, *dw_frame_t;
-
-
-typedef s_mc_pages_store_t *mc_pages_store_t;
-typedef s_mc_model_checker_t *mc_model_checker_t;
-typedef s_mc_address_space_t *mc_address_space_t;
-typedef s_mc_process_t *mc_process_t;
-typedef s_mc_snapshot_t *mc_snapshot_t;
-
-SG_BEGIN_DECL()
-extern mc_model_checker_t mc_model_checker;
-SG_END_DECL()
-
 #endif
diff --git a/src/mc/mc_forward.hpp b/src/mc/mc_forward.hpp
new file mode 100644 (file)
index 0000000..932d333
--- /dev/null
@@ -0,0 +1,44 @@
+/* Copyright (c) 2007-2014. The SimGrid Team.
+ * All rights reserved.                                                     */
+
+/* This program is free software; you can redistribute it and/or modify it
+ * under the terms of the license (GNU LGPL) which comes with this package. */
+
+/** \file mc_forward.hpp
+ *
+ *  Forward definitions for MC types
+ */
+
+#ifndef SIMGRID_MC_FORWARD_HPP
+#define SIMGRID_MC_FORWARD_HPP
+
+#ifndef __has_feature
+  #define __has_feature(x) 0
+#endif
+
+#if __has_feature(cxx_override_control)
+  #define MC_OVERRIDE override
+#else
+  #define MC_OVERRIDE
+#endif
+
+namespace simgrid {
+namespace mc {
+
+class PageStore;
+class ModelChecker;
+class AddressSpace;
+class Process;
+class Snapshot;
+class ObjectInformation;
+class Type;
+class Variable;
+class Frame;
+
+}
+}
+
+// TODO, try to get rid of the global ModelChecker variable
+extern simgrid::mc::ModelChecker* mc_model_checker;
+
+#endif
index 1df6abe..610ffac 100644 (file)
@@ -517,49 +517,6 @@ void MC_automaton_load(const char *file)
   xbt_automaton_load(_mc_property_automaton, file);
 }
 
-static void register_symbol(xbt_automaton_propositional_symbol_t symbol)
-{
-  if (mc_mode != MC_MODE_CLIENT)
-    return;
-  s_mc_register_symbol_message_t message;
-  message.type = MC_MESSAGE_REGISTER_SYMBOL;
-  const char* name = xbt_automaton_propositional_symbol_get_name(symbol);
-  if (strlen(name) + 1 > sizeof(message.name))
-    xbt_die("Symbol is too long");
-  strncpy(message.name, name, sizeof(message.name));
-  message.callback = xbt_automaton_propositional_symbol_get_callback(symbol);
-  message.data = xbt_automaton_propositional_symbol_get_data(symbol);
-  MC_client_send_message(&message, sizeof(message));
-}
-
-void MC_automaton_new_propositional_symbol(const char *id, int(*fct)(void))
-{
-  if (_mc_property_automaton == NULL)
-    _mc_property_automaton = xbt_automaton_new();
-
-  xbt_automaton_propositional_symbol_t symbol = xbt_automaton_propositional_symbol_new(_mc_property_automaton, id, fct);
-  register_symbol(symbol);
-}
-
-void MC_automaton_new_propositional_symbol_pointer(const char *id, int* value)
-{
-  if (_mc_property_automaton == NULL)
-    _mc_property_automaton = xbt_automaton_new();
-  xbt_automaton_propositional_symbol_t symbol = xbt_automaton_propositional_symbol_new_pointer(_mc_property_automaton, id, value);
-  register_symbol(symbol);
-}
-
-void MC_automaton_new_propositional_symbol_callback(const char* id,
-  xbt_automaton_propositional_symbol_callback_type callback,
-  void* data, xbt_automaton_propositional_symbol_free_function_type free_function)
-{
-  if (_mc_property_automaton == NULL)
-    _mc_property_automaton = xbt_automaton_new();
-  xbt_automaton_propositional_symbol_t symbol = xbt_automaton_propositional_symbol_new_callback(
-    _mc_property_automaton, id, callback, data, free_function);
-  register_symbol(symbol);
-}
-
 // TODO, fix cross-process access (this function is not used)
 void MC_dump_stacks(FILE* file)
 {
index 65ee9d2..602fced 100644 (file)
@@ -83,10 +83,10 @@ static void mc_hash_binary(hash_type * hash, const void *s, size_t len)
  *  \param type type of the variable
  * */
 static void mc_hash_value(hash_type * hash, mc_hashing_state * state,
-                          mc_object_info_t info, const void *address,
-                          dw_type_t type)
+                          simgrid::mc::ObjectInformation* info, const void *address,
+                          simgrid::mc::Type* type)
 {
-  mc_process_t process = &mc_model_checker->process();
+  simgrid::mc::Process* process = &mc_model_checker->process();
 top:
 
   switch (type->type) {
@@ -111,7 +111,7 @@ top:
         return;
 
       long element_count = type->element_count;
-      dw_type_t subtype = type->subtype;
+      simgrid::mc::Type* subtype = type->subtype;
       if (subtype == NULL) {
         XBT_DEBUG("Hash array without subtype");
         return;
@@ -145,7 +145,7 @@ top:
         return;
 
       unsigned int cursor = 0;
-      dw_type_t member;
+      simgrid::mc::Type* member;
       xbt_dynar_foreach(type->members, cursor, member) {
         XBT_DEBUG("Hash struct member %s", member->name);
         if (type->subtype == NULL)
@@ -189,7 +189,8 @@ top:
       }
 
       if (type->subtype == NULL) {
-        XBT_DEBUG("Missing type for %p (type=%s)", pointed, type->dw_type_id);
+        XBT_DEBUG("Missing type for %p (type=%s)",
+          pointed, type->type_id.c_str());
         return;
       }
 
@@ -207,19 +208,19 @@ top:
 }
 
 static void mc_hash_object_globals(hash_type * hash, mc_hashing_state * state,
-                                   mc_object_info_t info)
+                                   simgrid::mc::ObjectInformation* info)
 {
   unsigned int cursor = 0;
-  dw_variable_t variable;
+  simgrid::mc::Variable* variable;
   xbt_dynar_foreach(info->global_variables, cursor, variable) {
     XBT_DEBUG("Hash global variable %s", variable->name);
 
-    if (variable->type_origin == NULL) {
+    if (variable->type_id == NULL) {
       // Nothing
       continue;
     }
 
-    dw_type_t type = variable->type;
+    simgrid::mc::Type* type = variable->type;
     if (type == NULL) {
       // Nothing
       continue;
@@ -240,18 +241,18 @@ static void mc_hash_object_globals(hash_type * hash, mc_hashing_state * state,
 }
 
 static void mc_hash_stack_frame(mc_hash_t * hash,
-                                mc_object_info_t info,
-                                unw_cursor_t * unw_cursor, dw_frame_t frame,
+                                simgrid::mc::ObjectInformation* info,
+                                unw_cursor_t * unw_cursor, simgrid::mc::Frame* frame,
                                 char *frame_pointer, mc_hashing_state * state)
 {
 
   // return; // TEMP
 
   unsigned int cursor = 0;
-  dw_variable_t variable;
+  simgrid::mc::Variable* variable;
   xbt_dynar_foreach(frame->variables, cursor, variable) {
 
-    if (variable->type_origin == NULL) {
+    if (variable->type_id == NULL) {
       XBT_DEBUG("Hash local variable %s without type", variable->name);
       continue;
     }
@@ -267,7 +268,7 @@ static void mc_hash_stack_frame(mc_hash_t * hash,
                                             variable->object_info, unw_cursor,
                                             frame_pointer, NULL);
 
-    dw_type_t type = variable->type;
+    simgrid::mc::Type* type = variable->type;
     if (type == NULL) {
       XBT_DEBUG("Hash local variable %s without loctypeation", variable->name);
       continue;
@@ -290,7 +291,7 @@ static void mc_hash_stack(mc_hash_t * hash, mc_snapshot_stack_t stack,
 
     hash_update(*hash, stack_frame.ip);
 
-    mc_object_info_t info;
+    simgrid::mc::ObjectInformation* info;
     if (stack_frame.ip >= (unw_word_t) libsimgrid_info->start_exec
         && stack_frame.ip < (unw_word_t) libsimgrid_info->end_exec)
       info = libsimgrid_info;
index 57f77f7..a4b428f 100644 (file)
@@ -46,7 +46,6 @@ typedef struct s_mc_visited_pair{
 
 XBT_INTERNAL mc_pair_t MC_pair_new(void);
 XBT_INTERNAL void MC_pair_delete(mc_pair_t);
-XBT_INTERNAL void mc_pair_free_voidp(void *p);
 XBT_INTERNAL mc_visited_pair_t MC_visited_pair_new(int pair_num, xbt_automaton_state_t automaton_state, xbt_dynar_t atomic_propositions, mc_state_t graph_state);
 XBT_INTERNAL void MC_visited_pair_delete(mc_visited_pair_t p);
 
index d6f6fe4..76a2a26 100644 (file)
@@ -9,30 +9,45 @@
 
 #include <stdint.h>
 
+#include <vector>
+
 #include <libunwind.h>
 #include <dwarf.h>
 #include <elfutils/libdw.h>
 
 #include <simgrid_config.h>
 #include "mc_base.h"
-#include "mc_forward.h"
+#include "mc_forward.hpp"
 #include "AddressSpace.hpp"
 
-SG_BEGIN_DECL()
+namespace simgrid {
+namespace mc {
+
+typedef std::vector<Dwarf_Op> DwarfExpression;
 
-/** \brief a DWARF expression with optional validity contraints */
-typedef struct s_mc_expression {
-  size_t size;
-  Dwarf_Op* ops;
-  // Optional validity:
+
+/** \brief A DWARF expression with optional validity contraints */
+class LocationListEntry {
+public:
+  DwarfExpression expression;
   void* lowpc, *highpc;
-} s_mc_expression_t, *mc_expression_t;
 
-/** A location list (list of location expressions) */
-typedef struct s_mc_location_list {
-  size_t size;
-  mc_expression_t locations;
-} s_mc_location_list_t, *mc_location_list_t;
+  LocationListEntry() : lowpc(nullptr), highpc(nullptr) {}
+
+  bool valid_for_ip(unw_word_t ip)
+  {
+    return (this->lowpc == nullptr && this->highpc == nullptr)
+        || (ip >= (unw_word_t) this->lowpc
+            && ip < (unw_word_t) this->highpc);
+  }
+};
+
+typedef std::vector<LocationListEntry> LocationList;
+
+}
+}
+
+SG_BEGIN_DECL()
 
 /** A location is either a location in memory of a register location
  *
@@ -75,16 +90,20 @@ enum mc_location_type mc_get_location_type(mc_location_t location) {
   }
 }
 
-XBT_INTERNAL void mc_dwarf_resolve_location(mc_location_t location, mc_expression_t expression, mc_object_info_t object_info, unw_cursor_t* c, void* frame_pointer_address, mc_address_space_t address_space, int process_index);
-MC_SHOULD_BE_INTERNAL void mc_dwarf_resolve_locations(mc_location_t location, mc_location_list_t locations, mc_object_info_t object_info, unw_cursor_t* c, void* frame_pointer_address, mc_address_space_t address_space, int process_index);
-
-XBT_INTERNAL void mc_dwarf_expression_clear(mc_expression_t expression);
-XBT_INTERNAL void mc_dwarf_expression_init(mc_expression_t expression, size_t len, Dwarf_Op* ops);
-
-XBT_INTERNAL void mc_dwarf_location_list_clear(mc_location_list_t list);
-
-XBT_INTERNAL void mc_dwarf_location_list_init_from_expression(mc_location_list_t target, size_t len, Dwarf_Op* ops);
-XBT_INTERNAL void mc_dwarf_location_list_init(mc_location_list_t target, mc_object_info_t info, Dwarf_Die* die, Dwarf_Attribute* attr);
+XBT_INTERNAL void mc_dwarf_resolve_location(
+  mc_location_t location, simgrid::mc::DwarfExpression* expression,
+  simgrid::mc::ObjectInformation* object_info, unw_cursor_t* c,
+  void* frame_pointer_address, simgrid::mc::AddressSpace* address_space,
+  int process_index);
+MC_SHOULD_BE_INTERNAL void mc_dwarf_resolve_locations(
+  mc_location_t location, simgrid::mc::LocationList* locations,
+  simgrid::mc::ObjectInformation* object_info, unw_cursor_t* c,
+  void* frame_pointer_address, simgrid::mc::AddressSpace* address_space,
+  int process_index);
+
+XBT_INTERNAL void mc_dwarf_location_list_init(
+  simgrid::mc::LocationList*, simgrid::mc::ObjectInformation* info, Dwarf_Die* die,
+  Dwarf_Attribute* attr);
 
 #define MC_EXPRESSION_STACK_SIZE 64
 
@@ -102,8 +121,8 @@ typedef struct s_mc_expression_state {
 
   unw_cursor_t* cursor;
   void* frame_base;
-  mc_address_space_t address_space;
-  mc_object_info_t object_info;
+  simgrid::mc::AddressSpace* address_space;
+  simgrid::mc::ObjectInformation* object_info;
   int process_index;
 } s_mc_expression_state_t, *mc_expression_state_t;
 
@@ -111,8 +130,21 @@ MC_SHOULD_BE_INTERNAL int mc_dwarf_execute_expression(
   size_t n, const Dwarf_Op* ops, mc_expression_state_t state);
 
 MC_SHOULD_BE_INTERNAL void* mc_find_frame_base(
-  dw_frame_t frame, mc_object_info_t object_info, unw_cursor_t* unw_cursor);
+  simgrid::mc::Frame* frame, simgrid::mc::ObjectInformation* object_info, unw_cursor_t* unw_cursor);
 
 SG_END_DECL()
 
+namespace simgrid {
+namespace mc {
+
+inline
+int execute(DwarfExpression const& expression, mc_expression_state_t state)
+{
+  return mc_dwarf_execute_expression(
+    expression.size(), expression.data(), state);
+}
+
+}
+}
+
 #endif
index 21eaf14..59e7e7d 100644 (file)
  * @param snapshot Snapshot (or NULL)
  * @return Process address of the given member of the 'object' struct/class
  */
-void *mc_member_resolve(const void *base, dw_type_t type, dw_type_t member,
-                        mc_address_space_t address_space, int process_index)
+void *mc_member_resolve(const void *base, simgrid::mc::Type* type, simgrid::mc::Type* member,
+                        simgrid::mc::AddressSpace* address_space, int process_index)
 {
-  if (!member->location.size) {
-    return ((char *) base) + member->offset;
-  }
+  // TODO, get rid of this?
+  if (!member->has_offset_location())
+    return ((char *) base) + member->offset();
 
   s_mc_expression_state_t state;
   memset(&state, 0, sizeof(s_mc_expression_state_t));
@@ -33,8 +33,8 @@ void *mc_member_resolve(const void *base, dw_type_t type, dw_type_t member,
   state.stack[0] = (uintptr_t) base;
   state.process_index = process_index;
 
-  if (mc_dwarf_execute_expression
-      (member->location.size, member->location.ops, &state))
+  if (simgrid::mc::execute(
+      member->location_expression, &state))
     xbt_die("Error evaluating DWARF expression");
   if (state.stack_size == 0)
     xbt_die("No value on the stack");
index 21f2bdd..27844ad 100644 (file)
 
 #include <sys/types.h>
 
+#include <xbt/base.h>
+
 #include <simgrid_config.h>
-#include "mc_forward.h"
+#include "mc_forward.hpp"
 
 namespace simgrid {
 namespace mc {
@@ -40,7 +42,7 @@ std::vector<VmMap> get_memory_map(pid_t pid);
 extern "C" {
 
 XBT_INTERNAL void MC_find_object_address(
-  std::vector<simgrid::mc::VmMap> const& maps, mc_object_info_t result);
+  std::vector<simgrid::mc::VmMap> const& maps, simgrid::mc::ObjectInformation* result);
 
 }
 
index 2b00607..3d3703c 100644 (file)
 #include "mc_object_info.h"
 #include "mc_private.h"
 
-dw_frame_t MC_file_object_info_find_function(mc_object_info_t info, const void *ip)
+namespace simgrid {
+namespace mc {
+
+// Free functions
+
+static void mc_frame_free(void* frame)
+{
+  delete (simgrid::mc::Frame*)frame;
+}
+
+static void mc_type_free(void* t)
+{
+  delete (simgrid::mc::Type*)t;
+}
+
+// Type
+
+Type::Type()
+{
+  this->type = 0;
+  this->id = 0;
+  this->byte_size = 0;
+  this->element_count = 0;
+  this->is_pointer_type = 0;
+  this->type_id = 0;
+  this->subtype = nullptr;
+  this->full_type = nullptr;
+}
+
+// Type
+
+Variable::Variable()
+{
+  this->dwarf_offset = 0;
+  this->global = 0;
+  this->type = nullptr;
+  this->type_id = 0;
+  this->address = nullptr;
+  this->start_scope = 0;
+  this->object_info = nullptr;
+}
+
+// Frame
+
+Frame::Frame()
+{
+  this->tag = 0;
+  this->low_pc = nullptr;
+  this->high_pc = nullptr;
+  this->id = 0;
+  this->abstract_origin_id = 0;
+  this->object_info = nullptr;
+}
+
+// ObjectInformations
+
+ObjectInformation::ObjectInformation()
+{
+  this->flags = 0;
+  this->start = nullptr;
+  this->end = nullptr;
+  this->start_exec = nullptr;
+  this->end_exec = nullptr;
+  this->start_rw = nullptr;
+  this->end_rw = nullptr;
+  this->start_ro = nullptr;
+  this->end_ro = nullptr;
+}
+
+/** Find the DWARF offset for this ELF object
+ *
+ *  An offset is applied to address found in DWARF:
+ *
+ *  * for an executable obejct, addresses are virtual address
+ *    (there is no offset) i.e.
+ *    \f$\text{virtual address} = \{dwarf address}\f$;
+ *
+ *  * for a shared object, the addreses are offset from the begining
+ *    of the shared object (the base address of the mapped shared
+ *    object must be used as offset
+ *    i.e. \f$\text{virtual address} = \text{shared object base address}
+ *             + \text{dwarf address}\f$.
+ */
+void *ObjectInformation::base_address() const
 {
-  xbt_dynar_t dynar = info->functions_index;
-  mc_function_index_item_t base =
-      (mc_function_index_item_t) xbt_dynar_get_ptr(dynar, 0);
+  if (this->executable())
+    return nullptr;
+
+  void *result = this->start_exec;
+  if (this->start_rw != NULL && result > (void *) this->start_rw)
+    result = this->start_rw;
+  if (this->start_ro != NULL && result > (void *) this->start_ro)
+    result = this->start_ro;
+  return result;
+}
+
+/* Find a function by instruction pointer */
+simgrid::mc::Frame* ObjectInformation::find_function(const void *ip) const
+{
+  /* This is implemented by binary search on a sorted array.
+   *
+   * We do quite a lot ot those so we want this to be cache efficient.
+   * We pack the only information we need in the index entries in order
+   * to successfully do the binary search. We do not need the high_pc
+   * during the binary search (only at the end) so it is not included
+   * in the index entry. We could use parallel arrays as well.
+   *
+   * We cannot really use the std:: alogrithm for this.
+   * We could use std::binary_search by including the high_pc inside
+   * the FunctionIndexEntry.
+   */
+  const simgrid::mc::FunctionIndexEntry* base =
+    this->functions_index.data();
   int i = 0;
-  int j = xbt_dynar_length(dynar) - 1;
+  int j = this->functions_index.size() - 1;
   while (j >= i) {
     int k = i + ((j - i) / 2);
-    if (ip < base[k].low_pc) {
+
+    /* In most of the search, we do not dereference the base[k].function.
+     * This way the memory accesses are located in the base[k] array. */
+    if (ip < base[k].low_pc)
       j = k - 1;
-    } else if (ip >= base[k].high_pc) {
+    else if (k < j && ip >= base[k + 1].low_pc)
       i = k + 1;
-    } else {
+
+    /* At this point, the search is over.
+     * Either we have found the correct function or we do not know
+     * any function corresponding to this instruction address.
+     * Only at the point do we derefernce the function pointer. */
+    else if (ip < base[k].function->high_pc)
       return base[k].function;
-    }
+    else
+      return nullptr;
   }
-  return NULL;
+  return nullptr;
 }
 
-dw_variable_t MC_file_object_info_find_variable_by_name(mc_object_info_t info, const char* name)
+simgrid::mc::Variable* ObjectInformation::find_variable(const char* name) const
 {
-  unsigned int cursor = 0;
-  dw_variable_t variable;
-  xbt_dynar_foreach(info->global_variables, cursor, variable){
-    if(!strcmp(name, variable->name))
-      return variable;
-  }
+  for (simgrid::mc::Variable& variable : this->global_variables)
+    if(variable.name == name)
+      return &variable;
+  return nullptr;
+}
 
-  return NULL;
 }
+}
\ No newline at end of file
index b356884..c04b917 100644 (file)
 #ifndef SIMGRID_MC_OBJECT_INFO_H
 #define SIMGRID_MC_OBJECT_INFO_H
 
-#include <stdint.h>
-#include <stdbool.h>
+#include <cstdint>
+
+#include <string>
+#include <vector>
+#include <unordered_map>
 
 #include <simgrid_config.h>
 #include <xbt/dict.h>
 #include <xbt/dynar.h>
 
-#include "mc_forward.h"
+#include <elfutils/libdw.h>
+
+#include "mc_forward.hpp"
 #include "mc_location.h"
 #include "mc_process.h"
 #include "../smpi/private.h"
 
 // ***** Type
 
-typedef int e_dw_type_type;
+typedef int e_mc_type_type;
 
-struct s_dw_type {
-  s_dw_type();
-  ~s_dw_type();
+namespace simgrid {
+namespace mc {
 
-  e_dw_type_type type;
+/** Represents a type in the program
+ *
+ *  It is currently used to represent members of structs and unions as well.
+ */
+class Type {
+public:
+  Type();
+  Type(Type const& type) = default;
+  Type& operator=(Type const&) = default;
+  Type(Type&& type) = default;
+  Type& operator=(Type&&) = default;
+
+  e_mc_type_type type;
   Dwarf_Off id; /* Offset in the section (in hexadecimal form) */
-  char *name; /* Name of the type */
+  std::string name; /* Name of the type */
   int byte_size; /* Size in bytes */
   int element_count; /* Number of elements for array type */
-  char *dw_type_id; /* DW_AT_type id */
-  xbt_dynar_t members; /* if DW_TAG_structure_type, DW_TAG_class_type, DW_TAG_union_type*/
+  std::uint64_t type_id; /* DW_AT_type id */
+  std::vector<Type> members; /* if DW_TAG_structure_type, DW_TAG_class_type, DW_TAG_union_type*/
   int is_pointer_type;
 
   // Location (for members) is either of:
-  struct s_mc_expression location;
-  int offset;
-
-  dw_type_t subtype; // DW_AT_type
-  dw_type_t full_type; // The same (but more complete) type
+  simgrid::mc::DwarfExpression location_expression;
+
+  simgrid::mc::Type* subtype; // DW_AT_type
+  simgrid::mc::Type* full_type; // The same (but more complete) type
+
+  bool has_offset_location() const
+  {
+    return location_expression.size() == 1 &&
+      location_expression[0].atom == DW_OP_plus_uconst;
+  }
+
+  // TODO, check if this shortcut is really necessary
+  int offset() const
+  {
+    xbt_assert(this->has_offset_location());
+    return this->location_expression[0].number;
+  }
+
+  void offset(int new_offset)
+  {
+    Dwarf_Op op;
+    op.atom = DW_OP_plus_uconst;
+    op.number = new_offset;
+    this->location_expression = { op };
+  }
 };
 
-XBT_INTERNAL void dw_variable_free(dw_variable_t v);
-XBT_INTERNAL void dw_variable_free_voidp(void *t);
+}
+}
 
 // ***** Object info
 
@@ -58,14 +94,79 @@ typedef int mc_object_info_flags;
 #define MC_OBJECT_INFO_NONE 0
 #define MC_OBJECT_INFO_EXECUTABLE 1
 
-struct s_mc_object_info {
-  s_mc_object_info();
-  ~s_mc_object_info();
-  s_mc_object_info(s_mc_object_info const&) = delete;
-  s_mc_object_info& operator=(s_mc_object_info const&) = delete;
+namespace simgrid {
+namespace mc {
+
+class Variable {
+public:
+  Variable();
+
+  Dwarf_Off dwarf_offset; /* Global offset of the field. */
+  int global;
+  std::string name;
+  std::uint64_t type_id;
+  simgrid::mc::Type* type;
+
+  // Use either of:
+  simgrid::mc::LocationList location_list;
+  void* address;
+
+  size_t start_scope;
+  simgrid::mc::ObjectInformation* object_info;
+};
+
+class Frame {
+public:
+  Frame();
+
+  int tag;
+  std::string name;
+  void *low_pc;
+  void *high_pc;
+  simgrid::mc::LocationList frame_base;
+  std::vector<Variable> variables;
+  unsigned long int id; /* DWARF offset of the subprogram */
+  std::vector<Frame> scopes;
+  Dwarf_Off abstract_origin_id;
+  simgrid::mc::ObjectInformation* object_info;
+};
+
+/** An entry in the functions index
+ *
+ *  See the code of ObjectInformation::find_function.
+ */
+struct FunctionIndexEntry {
+  void* low_pc;
+  simgrid::mc::Frame* function;
+};
+
+/** Information about an (ELF) executable/sharedobject
+ *
+ *  This contain sall the information we have at runtime about an
+ *  executable/shared object in the target (modelchecked) process:
+ *  - where it is located in the virtual address space;
+ *  - where are located it's different memory mapping in the the
+ *    virtual address space ;
+ *  - all the debugging (DWARF) information,
+ *    - location of the functions,
+ *    - types
+ *  - etc.
+ *
+ *  It is not copyable because we are taking pointers to Types/Frames.
+ *  We'd have to update/rebuild some data structures in order to copy
+ *  successfully.
+ */
+
+class ObjectInformation {
+public:
+  ObjectInformation();
+
+  // Not copyable:
+  ObjectInformation(ObjectInformation const&) = delete;
+  ObjectInformation& operator=(ObjectInformation const&) = delete;
 
   mc_object_info_flags flags;
-  char* file_name;
+  std::string file_name;
   const void* start;
   const void *end;
   char *start_exec;
@@ -74,99 +175,52 @@ struct s_mc_object_info {
   char *end_rw; // Read-write segment
   char *start_ro;
   char *end_ro; // read-only segment
-  xbt_dict_t subprograms; // xbt_dict_t<origin as hexadecimal string, dw_frame_t>
-  xbt_dynar_t global_variables; // xbt_dynar_t<dw_variable_t>
-  xbt_dict_t types; // xbt_dict_t<origin as hexadecimal string, dw_type_t>
-  xbt_dict_t full_types_by_name; // xbt_dict_t<name, dw_type_t> (full defined type only)
-
-  // Here we sort the minimal information for an efficient (and cache-efficient)
-  // lookup of a function given an instruction pointer.
-  // The entries are sorted by low_pc and a binary search can be used to look them up.
-  xbt_dynar_t functions_index;
+  std::unordered_map<std::uint64_t, simgrid::mc::Frame> subprograms;
+  // TODO, remove the mutable (to remove it we'll have to add a lot of const everywhere)
+  mutable std::vector<simgrid::mc::Variable> global_variables;
+  std::unordered_map<std::uint64_t, simgrid::mc::Type> types;
+  std::unordered_map<std::string, simgrid::mc::Type*> full_types_by_name;
+
+  /** Index of functions by IP
+   *
+   * The entries are sorted by low_pc and a binary search can be used to look
+   * them up. Should we used a binary tree instead?
+   */
+  std::vector<FunctionIndexEntry> functions_index;
+
+  bool executable() const
+  {
+    return this->flags & MC_OBJECT_INFO_EXECUTABLE;
+  }
+
+  bool privatized() const
+  {
+    return this->executable() && smpi_privatize_global_variables;
+  }
+
+  void* base_address() const;
+
+  simgrid::mc::Frame* find_function(const void *ip) const;
+  // TODO, should be simgrid::mc::Variable*
+  simgrid::mc::Variable* find_variable(const char* name) const;
+
 };
 
-static inline __attribute__ ((always_inline))
-bool MC_object_info_executable(mc_object_info_t info)
-{
-  return info->flags & MC_OBJECT_INFO_EXECUTABLE;
 }
-
-static inline __attribute__ ((always_inline))
-bool MC_object_info_is_privatized(mc_object_info_t info)
-{
-  return info && MC_object_info_executable(info) && smpi_privatize_global_variables;
 }
 
-/** Find the DWARF offset for this ELF object
- *
- *  An offset is applied to address found in DWARF:
- *
- *  <ul>
- *    <li>for an executable obejct, addresses are virtual address
- *        (there is no offset) i.e. \f$\text{virtual address} = \{dwarf address}\f$;</li>
- *    <li>for a shared object, the addreses are offset from the begining
- *        of the shared object (the base address of the mapped shared
- *        object must be used as offset
- *        i.e. \f$\text{virtual address} = \text{shared object base address}
- *             + \text{dwarf address}\f$.</li>
- *
- */
-XBT_INTERNAL void* MC_object_base_address(mc_object_info_t info);
 
-XBT_INTERNAL std::shared_ptr<s_mc_object_info_t> MC_find_object_info(
+XBT_INTERNAL std::shared_ptr<simgrid::mc::ObjectInformation> MC_find_object_info(
   std::vector<simgrid::mc::VmMap> const& maps, const char* name, int executable);
+XBT_INTERNAL void MC_post_process_object_info(simgrid::mc::Process* process, simgrid::mc::ObjectInformation* info);
 
-XBT_INTERNAL void MC_free_object_info(mc_object_info_t* p);
-
-XBT_INTERNAL dw_frame_t MC_file_object_info_find_function(mc_object_info_t info, const void *ip);
-MC_SHOULD_BE_INTERNAL dw_variable_t MC_file_object_info_find_variable_by_name(mc_object_info_t info, const char* name);
-
-XBT_INTERNAL void MC_post_process_object_info(mc_process_t process, mc_object_info_t info);
-
-XBT_INTERNAL void MC_dwarf_get_variables(mc_object_info_t info);
-XBT_INTERNAL void MC_dwarf_get_variables_libdw(mc_object_info_t info);
+XBT_INTERNAL void MC_dwarf_get_variables(simgrid::mc::ObjectInformation* info);
+XBT_INTERNAL void MC_dwarf_get_variables_libdw(simgrid::mc::ObjectInformation* info);
 XBT_INTERNAL const char* MC_dwarf_attrname(int attr);
 XBT_INTERNAL const char* MC_dwarf_tagname(int tag);
 
-// Not used:
-XBT_INTERNAL char* get_type_description(mc_object_info_t info, char *type_name);
-
-XBT_INTERNAL void* mc_member_resolve(const void* base, dw_type_t type, dw_type_t member, mc_address_space_t snapshot, int process_index);
-
-struct s_dw_variable{
-  Dwarf_Off dwarf_offset; /* Global offset of the field. */
-  int global;
-  char *name;
-  char *type_origin;
-  dw_type_t type;
-
-  // Use either of:
-  s_mc_location_list_t locations;
-  void* address;
-
-  size_t start_scope;
-  mc_object_info_t object_info;
-
-};
-
-struct s_dw_frame{
-  int tag;
-  char *name;
-  void *low_pc;
-  void *high_pc;
-  s_mc_location_list_t frame_base;
-  xbt_dynar_t /* <dw_variable_t> */ variables; /* Cannot use dict, there may be several variables with the same name (in different lexical blocks)*/
-  unsigned long int id; /* DWARF offset of the subprogram */
-  xbt_dynar_t /* <dw_frame_t> */ scopes;
-  Dwarf_Off abstract_origin_id;
-  mc_object_info_t object_info;
-};
-
-struct s_mc_function_index_item {
-  void* low_pc, *high_pc;
-  dw_frame_t function;
-};
-
-XBT_INTERNAL void mc_frame_free(dw_frame_t freme);
+XBT_INTERNAL void* mc_member_resolve(
+  const void* base, simgrid::mc::Type* type, simgrid::mc::Type* member,
+  simgrid::mc::AddressSpace* snapshot, int process_index);
 
 #endif
index 7bb42f0..91dfcbd 100644 (file)
@@ -69,7 +69,7 @@ extern "C" {
  *  @param page_count       Number of pages of the region
  *  @param pagenos
  */
-void mc_restore_page_snapshot_region(mc_process_t process,
+void mc_restore_page_snapshot_region(simgrid::mc::Process* process,
   void* start_addr, simgrid::mc::PerPageCopy const& pages_copy)
 {
   for (size_t i = 0; i != pages_copy.page_count(); ++i) {
@@ -82,7 +82,7 @@ void mc_restore_page_snapshot_region(mc_process_t process,
 
 // ***** High level API
 
-void mc_region_restore_sparse(mc_process_t process, mc_mem_region_t reg)
+void mc_region_restore_sparse(simgrid::mc::Process* process, mc_mem_region_t reg)
 {
   xbt_assert(((reg->permanent_address().address()) & (xbt_pagesize-1)) == 0,
     "Not at the beginning of a page");
index 1a799ae..2cc2b04 100644 (file)
@@ -218,7 +218,7 @@ Process::Process(pid_t pid, int sockfd)
   }
 
   // Read std_heap (is a struct mdesc*):
-  dw_variable_t std_heap_var = process->find_variable("__mmalloc_default_mdp");
+  simgrid::mc::Variable* std_heap_var = process->find_variable("__mmalloc_default_mdp");
   if (!std_heap_var)
     xbt_die("No heap information in the target process");
   if(!std_heap_var->address)
@@ -377,7 +377,7 @@ void Process::init_memory_map_info()
       }
     }
 
-    std::shared_ptr<s_mc_object_info_t> info =
+    std::shared_ptr<simgrid::mc::ObjectInformation> info =
       MC_find_object_info(this->memory_map_, pathname, is_executable);
     this->object_infos.push_back(info);
     if (is_executable)
@@ -400,7 +400,7 @@ void Process::init_memory_map_info()
   XBT_DEBUG("Get debug information done !");
 }
 
-std::shared_ptr<s_mc_object_info_t> Process::find_object_info(remote_ptr<void> addr) const
+std::shared_ptr<simgrid::mc::ObjectInformation> Process::find_object_info(remote_ptr<void> addr) const
 {
   for (auto const& object_info : this->object_infos) {
     if (addr.address() >= (std::uint64_t)object_info->start
@@ -411,9 +411,9 @@ std::shared_ptr<s_mc_object_info_t> Process::find_object_info(remote_ptr<void> a
   return NULL;
 }
 
-std::shared_ptr<s_mc_object_info_t> Process::find_object_info_exec(remote_ptr<void> addr) const
+std::shared_ptr<ObjectInformation> Process::find_object_info_exec(remote_ptr<void> addr) const
 {
-  for (std::shared_ptr<s_mc_object_info> const& info : this->object_infos) {
+  for (std::shared_ptr<ObjectInformation> const& info : this->object_infos) {
     if (addr.address() >= (std::uint64_t) info->start_exec
         && addr.address() <= (std::uint64_t) info->end_exec) {
       return info;
@@ -422,9 +422,9 @@ std::shared_ptr<s_mc_object_info_t> Process::find_object_info_exec(remote_ptr<vo
   return nullptr;
 }
 
-std::shared_ptr<s_mc_object_info_t> Process::find_object_info_rw(remote_ptr<void> addr) const
+std::shared_ptr<ObjectInformation> Process::find_object_info_rw(remote_ptr<void> addr) const
 {
-  for (std::shared_ptr<s_mc_object_info> const& info : this->object_infos) {
+  for (std::shared_ptr<ObjectInformation> const& info : this->object_infos) {
     if (addr.address() >= (std::uint64_t)info->start_rw
         && addr.address() <= (std::uint64_t)info->end_rw) {
       return info;
@@ -433,32 +433,29 @@ std::shared_ptr<s_mc_object_info_t> Process::find_object_info_rw(remote_ptr<void
   return nullptr;
 }
 
-dw_frame_t Process::find_function(remote_ptr<void> ip) const
+simgrid::mc::Frame* Process::find_function(remote_ptr<void> ip) const
 {
-  std::shared_ptr<s_mc_object_info_t> info = this->find_object_info_exec(ip);
-  if (!info)
-    return nullptr;
-  else
-    return MC_file_object_info_find_function(info.get(), (void*) ip.address());
+  std::shared_ptr<simgrid::mc::ObjectInformation> info = this->find_object_info_exec(ip);
+  return info ? info->find_function((void*) ip.address()) : nullptr;
 }
 
 /** Find (one occurence of) the named variable definition
  */
-dw_variable_t Process::find_variable(const char* name) const
+simgrid::mc::Variable* Process::find_variable(const char* name) const
 {
   // First lookup the variable in the executable shared object.
   // A global variable used directly by the executable code from a library
   // is reinstanciated in the executable memory .data/.bss.
   // We need to look up the variable in the execvutable first.
   if (this->binary_info) {
-    std::shared_ptr<s_mc_object_info_t> const& info = this->binary_info;
-    dw_variable_t var = MC_file_object_info_find_variable_by_name(info.get(), name);
+    std::shared_ptr<simgrid::mc::ObjectInformation> const& info = this->binary_info;
+    simgrid::mc::Variable* var = info->find_variable(name);
     if (var)
       return var;
   }
 
-  for (std::shared_ptr<s_mc_object_info_t> const& info : this->object_infos) {
-    dw_variable_t var = MC_file_object_info_find_variable_by_name(info.get(), name);
+  for (std::shared_ptr<simgrid::mc::ObjectInformation> const& info : this->object_infos) {
+    simgrid::mc::Variable* var = info->find_variable(name);
     if (var)
       return var;
   }
@@ -468,7 +465,7 @@ dw_variable_t Process::find_variable(const char* name) const
 
 void Process::read_variable(const char* name, void* target, size_t size) const
 {
-  dw_variable_t var = this->find_variable(name);
+  simgrid::mc::Variable* var = this->find_variable(name);
   if (!var->address)
     xbt_die("No simple location for this variable");
   if (!var->type->full_type)
@@ -518,10 +515,10 @@ const void *Process::read_bytes(void* buffer, std::size_t size,
   AddressSpace::ReadMode mode) const
 {
   if (process_index != simgrid::mc::ProcessIndexDisabled) {
-    std::shared_ptr<s_mc_object_info_t> const& info =
+    std::shared_ptr<simgrid::mc::ObjectInformation> const& info =
       this->find_object_info_rw((void*)address.address());
     // Segment overlap is not handled.
-    if (MC_object_info_is_privatized(info.get())) {
+    if (info.get() && info.get()->privatized()) {
       if (process_index < 0)
         xbt_die("Missing process index");
       if (process_index >= (int) MC_smpi_process_count())
index b357134..8aee3c0 100644 (file)
@@ -27,7 +27,7 @@
 #include "simix/popping_private.h"
 #include "simix/smx_private.h"
 
-#include "mc_forward.h"
+#include "mc_forward.hpp"
 #include "mc_base.h"
 #include "mc_mmalloc.h" // std_heap
 #include "mc_memory_map.h"
@@ -89,11 +89,11 @@ public:
   void clear_bytes(remote_ptr<void> address, size_t len);
 
   // Debug information:
-  std::shared_ptr<s_mc_object_info_t> find_object_info(remote_ptr<void> addr) const;
-  std::shared_ptr<s_mc_object_info_t> find_object_info_exec(remote_ptr<void> addr) const;
-  std::shared_ptr<s_mc_object_info_t> find_object_info_rw(remote_ptr<void> addr) const;
-  dw_frame_t find_function(remote_ptr<void> ip) const;
-  dw_variable_t find_variable(const char* name) const;
+  std::shared_ptr<simgrid::mc::ObjectInformation> find_object_info(remote_ptr<void> addr) const;
+  std::shared_ptr<simgrid::mc::ObjectInformation> find_object_info_exec(remote_ptr<void> addr) const;
+  std::shared_ptr<simgrid::mc::ObjectInformation> find_object_info_rw(remote_ptr<void> addr) const;
+  simgrid::mc::Frame* find_function(remote_ptr<void> ip) const;
+  simgrid::mc::Variable* find_variable(const char* name) const;
 
   // Heap access:
   xbt_mheap_t get_heap()
@@ -173,10 +173,10 @@ private:
   std::vector<IgnoredRegion> ignored_regions_;
 
 public: // object info
-  // TODO, make private (first, objectify mc_object_info_t)
-  std::vector<std::shared_ptr<s_mc_object_info_t>> object_infos;
-  std::shared_ptr<s_mc_object_info_t> libsimgrid_info;
-  std::shared_ptr<s_mc_object_info_t> binary_info;
+  // TODO, make private (first, objectify simgrid::mc::ObjectInformation*)
+  std::vector<std::shared_ptr<simgrid::mc::ObjectInformation>> object_infos;
+  std::shared_ptr<simgrid::mc::ObjectInformation> libsimgrid_info;
+  std::shared_ptr<simgrid::mc::ObjectInformation> binary_info;
 
 public: // Copies of MCed SMX data structures
   /** Copy of `simix_global->process_list`
@@ -218,7 +218,8 @@ public: // Libunwind-data
   /** Full-featured MC-aware libunwind address space for the process
    *
    *  This address space is using a mc_unw_context_t
-   *  (with mc_process_t/mc_address_space_t and unw_context_t).
+   *  (with simgrid::mc::Process* / simgrid::mc::AddressSpace*
+   *  and unw_context_t).
    */
   unw_addr_space_t unw_addr_space;
 
index bd5ab1f..8e47e89 100644 (file)
@@ -11,7 +11,7 @@
 
 #include <simgrid_config.h>
 #include <xbt/dict.h>
-#include "mc_forward.h"
+#include "mc_forward.hpp"
 #include "mc_state.h"
 
 SG_BEGIN_DECL()
index 020e170..b869b19 100644 (file)
@@ -14,6 +14,8 @@
 #include <sys/signalfd.h>
 
 #include <xbt/log.h>
+#include <xbt/automaton.h>
+#include <xbt/automaton.hpp>
 
 #include "ModelChecker.hpp"
 #include "mc_protocol.h"
@@ -22,6 +24,7 @@
 #include "mc_ignore.h"
 #include "mcer_ignore.h"
 #include "mc_exit.h"
+#include "mc/mc_liveness.h"
 
 using simgrid::mc::remote;
 
@@ -35,20 +38,6 @@ XBT_LOG_NEW_DEFAULT_SUBCATEGORY(mc_server, mc, "MC server logic");
 
 mc_server_t mc_server;
 
-struct mc_symbol_pointer_callback
-{
-  mc_process_t process;
-  void* value;
-};
-
-static int mc_symbol_pointer_callback_evaluate(void* p)
-{
-  struct mc_symbol_pointer_callback* callback = (struct mc_symbol_pointer_callback*) p;
-  int value;
-  callback->process->read_bytes(&value, sizeof(value), remote(callback->value));
-  return value;
-}
-
 s_mc_server::s_mc_server(pid_t pid, int socket)
 {
   this->pid = pid;
@@ -95,7 +84,7 @@ void s_mc_server::shutdown()
 {
   XBT_DEBUG("Shuting down model-checker");
 
-  mc_process_t process = &mc_model_checker->process();
+  simgrid::mc::Process* process = &mc_model_checker->process();
   int status = process->status();
   if (process->running()) {
     XBT_DEBUG("Killing process");
@@ -123,7 +112,7 @@ void s_mc_server::exit()
   }
 }
 
-void s_mc_server::resume(mc_process_t process)
+void s_mc_server::resume(simgrid::mc::Process* process)
 {
   int res = process->send_message(MC_MESSAGE_CONTINUE);
   if (res)
@@ -223,15 +212,20 @@ bool s_mc_server::handle_events()
             xbt_die("Broken message");
           memcpy(&message, buffer, sizeof(message));
           if (message.callback)
-            xbt_die("Support for callbacks/functions symbols not implemented in client/server mode.");
+            xbt_die("Support for client-side function proposition is not implemented.");
           XBT_DEBUG("Received symbol: %s", message.name);
 
-          struct mc_symbol_pointer_callback* callback = xbt_new(struct mc_symbol_pointer_callback, 1);
-          callback->process = &mc_model_checker->process();
-          callback->value   = message.data;
+          if (_mc_property_automaton == NULL)
+            _mc_property_automaton = xbt_automaton_new();
+
+          simgrid::mc::Process* process = &mc_model_checker->process();
+          simgrid::mc::remote_ptr<int> address
+            = simgrid::mc::remote((int*) message.data);
+          simgrid::xbt::add_proposition(_mc_property_automaton,
+            message.name,
+            [process, address]() { return process->read(address); }
+            );
 
-          MC_automaton_new_propositional_symbol_callback(message.name,
-            mc_symbol_pointer_callback_evaluate, callback, free);
           break;
         }
 
@@ -336,7 +330,7 @@ void s_mc_server::on_signal(const struct signalfd_siginfo* info)
   }
 }
 
-void MC_server_wait_client(mc_process_t process)
+void MC_server_wait_client(simgrid::mc::Process* process)
 {
   mc_server->resume(process);
   while (mc_model_checker->process().running()) {
@@ -345,7 +339,7 @@ void MC_server_wait_client(mc_process_t process)
   }
 }
 
-void MC_server_simcall_handle(mc_process_t process, unsigned long pid, int value)
+void MC_server_simcall_handle(simgrid::mc::Process* process, unsigned long pid, int value)
 {
   s_mc_simcall_handle_message m;
   memset(&m, 0, sizeof(m));
index e2c1a23..7a54ecc 100644 (file)
@@ -28,8 +28,8 @@ typedef struct s_mc_server s_mc_server_t, *mc_server_t;
 
 extern mc_server_t mc_server;
 
-XBT_INTERNAL void MC_server_wait_client(mc_process_t process);
-XBT_INTERNAL void MC_server_simcall_handle(mc_process_t process, unsigned long pid, int value);
+XBT_INTERNAL void MC_server_wait_client(simgrid::mc::Process* process);
+XBT_INTERNAL void MC_server_simcall_handle(simgrid::mc::Process* process, unsigned long pid, int value);
 
 XBT_INTERNAL void MC_server_loop(mc_server_t server);
 
@@ -47,7 +47,7 @@ public:
   void start();
   void shutdown();
   void exit();
-  void resume(mc_process_t process);
+  void resume(simgrid::mc::Process* process);
   void loop();
   bool handle_events();
 protected:
index 8372875..805d655 100644 (file)
@@ -57,7 +57,7 @@ mc_smx_process_info_t MC_smx_process_get_info(smx_process_t p)
  *  @param remote_swag Address of the process SWAG in the remote list
  */
 static void MC_process_refresh_simix_process_list(
-  mc_process_t process,
+  simgrid::mc::Process* process,
   xbt_dynar_t target, xbt_swag_t remote_swag)
 {
   // swag = REMOTE(*simix_global->process_list)
@@ -84,7 +84,7 @@ static void MC_process_refresh_simix_process_list(
   assert(i == swag.count);
 }
 
-void MC_process_smx_refresh(mc_process_t process)
+void MC_process_smx_refresh(simgrid::mc::Process* process)
 {
   xbt_assert(mc_mode == MC_MODE_SERVER);
   xbt_assert(!process->is_self());
@@ -178,7 +178,7 @@ const char* MC_smx_process_get_host_name(smx_process_t p)
   if (mc_mode == MC_MODE_CLIENT)
     return SIMIX_host_get_name(p->smx_host);
 
-  mc_process_t process = &mc_model_checker->process();
+  simgrid::mc::Process* process = &mc_model_checker->process();
 
   // Currently, smx_host_t = xbt_dictelm_t.
   // TODO, add an static_assert on this if switching to C++
@@ -199,7 +199,7 @@ const char* MC_smx_process_get_host_name(smx_process_t p)
 
 const char* MC_smx_process_get_name(smx_process_t p)
 {
-  mc_process_t process = &mc_model_checker->process();
+  simgrid::mc::Process* process = &mc_model_checker->process();
   if (mc_mode == MC_MODE_CLIENT)
     return p->name;
   if (!p->name)
index 49d69be..c9cdd7a 100644 (file)
@@ -33,7 +33,7 @@
  *
  * The process lists are currently refreshed each time MCed code is executed.
  * We don't try to give a persistent MCer address for a given MCed process.
- * For this reason, a MCer mc_process_t is currently not reusable after
+ * For this reason, a MCer simgrid::mc::Process* is currently not reusable after
  * MCed code.
  */
 
@@ -51,7 +51,7 @@ struct s_mc_smx_process_info {
 
 XBT_INTERNAL xbt_dynar_t MC_smx_process_info_list_new(void);
 
-XBT_INTERNAL void MC_process_smx_refresh(mc_process_t process);
+XBT_INTERNAL void MC_process_smx_refresh(simgrid::mc::Process* process);
 
 /** Get the issuer of  a simcall (`req->issuer`)
  *
index bfc3d89..3277f97 100644 (file)
@@ -24,7 +24,7 @@ extern "C" {
  *         (or NULL if it does not belong to any snapshot region)
  * */
 mc_mem_region_t mc_get_snapshot_region(
-  const void* addr, const s_mc_snapshot_t* snapshot, int process_index)
+  const void* addr, const simgrid::mc::Snapshot* snapshot, int process_index)
 {
   size_t n = snapshot->snapshot_regions.size();
   for (size_t i = 0; i != n; ++i) {
index fc2ea78..418278d 100644 (file)
@@ -19,7 +19,7 @@
 #include <xbt/asserts.h>
 #include <xbt/dynar.h>
 
-#include "mc_forward.h"
+#include "mc_forward.hpp"
 #include "ModelChecker.hpp"
 #include "PageStore.hpp"
 #include "mc_mmalloc.h"
@@ -31,7 +31,7 @@ SG_BEGIN_DECL()
 
 // ***** Snapshot region
 
-XBT_INTERNAL void mc_region_restore_sparse(mc_process_t process, mc_mem_region_t reg);
+XBT_INTERNAL void mc_region_restore_sparse(simgrid::mc::Process* process, mc_mem_region_t reg);
 
 static inline __attribute__((always_inline))
 void* mc_translate_address_region_chunked(uintptr_t addr, mc_mem_region_t region)
@@ -72,7 +72,7 @@ void* mc_translate_address_region(uintptr_t addr, mc_mem_region_t region, int pr
 }
 
 XBT_INTERNAL mc_mem_region_t mc_get_snapshot_region(
-  const void* addr, const s_mc_snapshot_t *snapshot, int process_index);
+  const void* addr, const simgrid::mc::Snapshot *snapshot, int process_index);
 
 }
 
@@ -104,16 +104,16 @@ typedef struct s_mc_stack_frame {
   /** Stack pointer */
   unw_word_t sp;
   unw_word_t frame_base;
-  dw_frame_t frame;
+  simgrid::mc::Frame* frame;
   std::string frame_name;
   unw_cursor_t unw_cursor;
 } s_mc_stack_frame_t, *mc_stack_frame_t;
 
 typedef struct s_local_variable{
-  dw_frame_t subprogram;
+  simgrid::mc::Frame* subprogram;
   unsigned long ip;
   std::string name;
-  dw_type_t type;
+  simgrid::mc::Type* type;
   void *address;
   int region;
 } s_local_variable_t, *local_variable_t;
@@ -147,7 +147,7 @@ public:
     remote_ptr<void> address, int process_index = ProcessIndexAny,
     ReadMode mode = Normal) const MC_OVERRIDE;
 public: // To be private
-  mc_process_t process;
+  simgrid::mc::Process* process;
   int num_state;
   size_t heap_bytes_used;
   std::vector<std::unique_ptr<s_mc_mem_region_t>> snapshot_regions;
@@ -181,7 +181,7 @@ XBT_INTERNAL mc_snapshot_t MC_take_snapshot(int num_state);
 XBT_INTERNAL void MC_restore_snapshot(mc_snapshot_t);
 
 XBT_INTERNAL void mc_restore_page_snapshot_region(
-  mc_process_t process,
+  simgrid::mc::Process* process,
   void* start_addr, simgrid::mc::PerPageCopy const& pagenos);
 
 MC_SHOULD_BE_INTERNAL const void* MC_region_read_fragmented(
index c408e2a..0d78305 100644 (file)
@@ -74,7 +74,7 @@ static int get_dyn_info_list_addr(unw_addr_space_t as,
 
 /** Read from the target address space memory (libunwind method)
  *
- *  Delegates to the `mc_process_t`.
+ *  Delegates to the `simgrid::mc::Process*`.
  */
 static int access_mem(unw_addr_space_t as,
               unw_word_t addr, unw_word_t *valp,
@@ -164,12 +164,12 @@ static int get_proc_name(unw_addr_space_t as,
               void* arg)
 {
   mc_unw_context_t context = (mc_unw_context_t) arg;
-  dw_frame_t frame = context->process->find_function(remote(addr));
+  simgrid::mc::Frame* frame = context->process->find_function(remote(addr));
   if (!frame)
     return - UNW_ENOINFO;
   *offp = (unw_word_t) frame->low_pc - addr;
 
-  strncpy(bufp, frame->name, buf_len);
+  strncpy(bufp, frame->name.c_str(), buf_len);
   if (bufp[buf_len - 1]) {
     bufp[buf_len - 1] = 0;
     return -UNW_ENOMEM;
@@ -195,7 +195,7 @@ unw_accessors_t mc_unw_accessors =
 // ***** Context management
 
 int mc_unw_init_context(
-  mc_unw_context_t context, mc_process_t process, unw_context_t* c)
+  mc_unw_context_t context, simgrid::mc::Process* process, unw_context_t* c)
 {
   context->address_space = process;
   context->process = process;
@@ -223,9 +223,9 @@ int mc_unw_init_cursor(unw_cursor_t *cursor, mc_unw_context_t context)
 {
   if (!context->process || !context->address_space)
     return -UNW_EUNSPEC;
-  mc_address_space_t as = context->address_space;
+  simgrid::mc::AddressSpace* as = context->address_space;
 
-  mc_process_t process = dynamic_cast<mc_process_t>(as);
+  simgrid::mc::Process* process = dynamic_cast<simgrid::mc::Process*>(as);
   if (process && process->is_self())
     return unw_init_local(cursor, &context->context);
 
index eac812d..7928d0b 100644 (file)
@@ -17,7 +17,7 @@
  *
  *  This component implements the libunwind API for he model-checker:
  *
- *    * reading memory from a mc_address_space_t;
+ *    * reading memory from a simgrid::mc::AddressSpace*;
  *
  *    * reading stack registers from a saved snapshot (context).
  *
@@ -48,7 +48,7 @@ extern unw_accessors_t mc_unw_vmread_accessors;
 
 /** Virtual table for our `libunwind` implementation
  *
- *  Stack unwinding on a `mc_process_t` (for memory, unwinding information)
+ *  Stack unwinding on a `simgrid::mc::Process*` (for memory, unwinding information)
  *  and `ucontext_t` (for processor registers).
  *
  *  It works with the `s_mc_unw_context_t` context.
@@ -60,14 +60,14 @@ extern XBT_INTERNAL unw_accessors_t mc_unw_accessors;
 /** A `libunwind` context
  */
 typedef struct s_mc_unw_context {
-  mc_address_space_t address_space;
-  mc_process_t       process;
+  simgrid::mc::AddressSpace* address_space;
+  simgrid::mc::Process*       process;
   unw_context_t      context;
 } s_mc_unw_context_t, *mc_unw_context_t;
 
 /** Initialises an already allocated context */
 XBT_INTERNAL int mc_unw_init_context(
-  mc_unw_context_t context, mc_process_t process, unw_context_t* c);
+  mc_unw_context_t context, simgrid::mc::Process* process, unw_context_t* c);
 
 // ***** Libunwind cursor
 
index 4b19189..59c43c5 100644 (file)
@@ -54,7 +54,7 @@ void visited_state_free_voidp(void *s)
  */
 static mc_visited_state_t visited_state_new()
 {
-  mc_process_t process = &(mc_model_checker->process());
+  simgrid::mc::Process* process = &(mc_model_checker->process());
   mc_visited_state_t new_state = xbt_new0(s_mc_visited_state_t, 1);
   new_state->heap_bytes_used = mmalloc_get_bytes_used_remote(
     process->get_heap()->heaplimit,
@@ -76,7 +76,7 @@ static mc_visited_state_t visited_state_new()
 
 mc_visited_pair_t MC_visited_pair_new(int pair_num, xbt_automaton_state_t automaton_state, xbt_dynar_t atomic_propositions, mc_state_t graph_state)
 {
-  mc_process_t process = &(mc_model_checker->process());
+  simgrid::mc::Process* process = &(mc_model_checker->process());
   mc_visited_pair_t pair = NULL;
   pair = xbt_new0(s_mc_visited_pair_t, 1);
   pair->graph_state = graph_state;
index 7742139..5f1780b 100644 (file)
@@ -4,6 +4,8 @@
 /* This program is free software; you can redistribute it and/or modify it
  * under the terms of the license (GNU LGPL) which comes with this package. */
 
+#include <xbt/sysdep.h>
+
 #include "mc/AddressSpace.hpp"
 #include "mc_xbt.hpp"
 
index ed25728..1de7873 100644 (file)
@@ -111,24 +111,24 @@ void MC_heap_region_ignore_remove(void *address, size_t size)
 
 void MCer_ignore_global_variable(const char *name)
 {
-  mc_process_t process = &mc_model_checker->process();
+  simgrid::mc::Process* process = &mc_model_checker->process();
   xbt_assert(!process->object_infos.empty(), "MC subsystem not initialized");
 
-  for (std::shared_ptr<s_mc_object_info_t> const& info : process->object_infos) {
+  for (std::shared_ptr<simgrid::mc::ObjectInformation> const& info : process->object_infos) {
 
     // Binary search:
     int start = 0;
-    int end = xbt_dynar_length(info->global_variables) - 1;
+    int end = info->global_variables.size() - 1;
     while (start <= end) {
       unsigned int cursor = (start + end) / 2;
-      dw_variable_t current_var =
-          (dw_variable_t) xbt_dynar_get_as(info->global_variables,
-                                           cursor, dw_variable_t);
-      if (strcmp(current_var->name, name) == 0) {
-        xbt_dynar_remove_at(info->global_variables, cursor, NULL);
+      simgrid::mc::Variable* current_var = &info->global_variables[cursor];
+      int cmp = strcmp(current_var->name.c_str(), name);
+      if (cmp == 0) {
+        info->global_variables.erase(
+          info->global_variables.begin() + cursor);
         start = 0;
-        end = xbt_dynar_length(info->global_variables) - 1;
-      } else if (strcmp(current_var->name, name) < 0) {
+        end = info->global_variables.size() - 1;
+      } else if (cmp < 0) {
         start = cursor + 1;
       } else {
         end = cursor - 1;
@@ -141,32 +141,29 @@ void MCer_ignore_global_variable(const char *name)
 
 static void mc_ignore_local_variable_in_scope(const char *var_name,
                                               const char *subprogram_name,
-                                              dw_frame_t subprogram,
-                                              dw_frame_t scope);
+                                              simgrid::mc::Frame* subprogram,
+                                              simgrid::mc::Frame* scope);
 static void MC_ignore_local_variable_in_object(const char *var_name,
                                                const char *subprogram_name,
-                                               mc_object_info_t info);
+                                               simgrid::mc::ObjectInformation* info);
 
 void MC_ignore_local_variable(const char *var_name, const char *frame_name)
 {
-  mc_process_t process = &mc_model_checker->process();
+  simgrid::mc::Process* process = &mc_model_checker->process();
   if (strcmp(frame_name, "*") == 0)
     frame_name = NULL;
 
-  for (std::shared_ptr<s_mc_object_info_t> const& info : process->object_infos)
+  for (std::shared_ptr<simgrid::mc::ObjectInformation> const& info : process->object_infos)
     MC_ignore_local_variable_in_object(var_name, frame_name, info.get());
 }
 
 static void MC_ignore_local_variable_in_object(const char *var_name,
                                                const char *subprogram_name,
-                                               mc_object_info_t info)
+                                               simgrid::mc::ObjectInformation* info)
 {
-  xbt_dict_cursor_t cursor2;
-  dw_frame_t frame;
-  char *key;
-  xbt_dict_foreach(info->subprograms, cursor2, key, frame) {
-    mc_ignore_local_variable_in_scope(var_name, subprogram_name, frame, frame);
-  }
+  for (auto& entry : info->subprograms)
+    mc_ignore_local_variable_in_scope(
+      var_name, subprogram_name, &entry.second, &entry.second);
 }
 
 /** \brief Ignore a local variable in a scope
@@ -182,34 +179,33 @@ static void MC_ignore_local_variable_in_object(const char *var_name,
  */
 static void mc_ignore_local_variable_in_scope(const char *var_name,
                                               const char *subprogram_name,
-                                              dw_frame_t subprogram,
-                                              dw_frame_t scope)
+                                              simgrid::mc::Frame* subprogram,
+                                              simgrid::mc::Frame* scope)
 {
   // Processing of direct variables:
 
   // If the current subprogram matches the given name:
-  if (!subprogram_name ||
-      (subprogram->name && strcmp(subprogram_name, subprogram->name) == 0)) {
+  if (subprogram_name == nullptr ||
+      (!subprogram->name.empty()
+        && subprogram->name == subprogram_name)) {
 
     // Try to find the variable and remove it:
     int start = 0;
-    int end = xbt_dynar_length(scope->variables) - 1;
+    int end = scope->variables.size() - 1;
 
     // Dichotomic search:
     while (start <= end) {
       int cursor = (start + end) / 2;
-      dw_variable_t current_var =
-          (dw_variable_t) xbt_dynar_get_as(scope->variables, cursor,
-                                           dw_variable_t);
+      simgrid::mc::Variable* current_var = &scope->variables[cursor];
 
-      int compare = strcmp(current_var->name, var_name);
+      int compare = strcmp(current_var->name.c_str(), var_name);
       if (compare == 0) {
         // Variable found, remove it:
-        xbt_dynar_remove_at(scope->variables, cursor, NULL);
+        scope->variables.erase(scope->variables.begin() + cursor);
 
         // and start again:
         start = 0;
-        end = xbt_dynar_length(scope->variables) - 1;
+        end = scope->variables.size() - 1;
       } else if (compare < 0) {
         start = cursor + 1;
       } else {
@@ -219,17 +215,15 @@ static void mc_ignore_local_variable_in_scope(const char *var_name,
 
   }
   // And recursive processing in nested scopes:
-  unsigned cursor = 0;
-  dw_frame_t nested_scope = NULL;
-  xbt_dynar_foreach(scope->scopes, cursor, nested_scope) {
+  for (simgrid::mc::Frame& nested_scope : scope->scopes) {
     // The new scope may be an inlined subroutine, in this case we want to use its
     // namespaced name in recursive calls:
-    dw_frame_t nested_subprogram =
-        nested_scope->tag ==
-        DW_TAG_inlined_subroutine ? nested_scope : subprogram;
+    simgrid::mc::Frame* nested_subprogram =
+        nested_scope.tag ==
+        DW_TAG_inlined_subroutine ? &nested_scope : subprogram;
 
     mc_ignore_local_variable_in_scope(var_name, subprogram_name,
-                                      nested_subprogram, nested_scope);
+                                      nested_subprogram, &nested_scope);
   }
 }
 
index 52bfa70..1aea183 100644 (file)
@@ -4,7 +4,9 @@
 /* This program is free software; you can redistribute it and/or modify it
  * under the terms of the license (GNU LGPL) which comes with this package. */
 
-#include <stdlib.h>
+#include <cstdlib>
+#include <cstdio>
+#include <cstring>
 
 #include <sys/types.h>
 
@@ -26,9 +28,9 @@ std::vector<VmMap> get_memory_map(pid_t pid)
   /* Open the actual process's proc maps file and create the memory_map_t */
   /* to be returned. */
   char* path = bprintf("/proc/%i/maps", (int) pid);
-  FILE *fp = fopen(path, "r");
+  FILE *fp = std::fopen(path, "r");
   if(fp == NULL)
-    perror("fopen failed");
+    std::perror("fopen failed");
   xbt_assert(fp,
     "Cannot open %s to investigate the memory map of the process.", path);
   free(path);
@@ -39,7 +41,7 @@ std::vector<VmMap> get_memory_map(pid_t pid)
   /* Read one line at the time, parse it and add it to the memory map to be returned */
   ssize_t read; /* Number of bytes readed */
   char* line = NULL;
-  size_t n = 0; /* Amount of bytes to read by xbt_getline */
+  std::size_t n = 0; /* Amount of bytes to read by xbt_getline */
   while ((read = xbt_getline(&line, &n, fp)) != -1) {
 
     //fprintf(stderr,"%s", line);
@@ -54,7 +56,7 @@ std::vector<VmMap> get_memory_map(pid_t pid)
 
     int i;
     for (i = 1; i < 6 && lfields[i - 1] != NULL; i++) {
-      lfields[i] = strtok(NULL, " ");
+      lfields[i] = std::strtok(NULL, " ");
     }
 
     /* Check to see if we got the expected amount of columns */
@@ -63,28 +65,28 @@ std::vector<VmMap> get_memory_map(pid_t pid)
 
     /* Ok we are good enough to try to get the info we need */
     /* First get the start and the end address of the map   */
-    char *tok = strtok(lfields[0], "-");
+    char *tok = std::strtok(lfields[0], "-");
     if (tok == NULL)
       xbt_abort();
 
     VmMap memreg;
     char *endptr;
-    memreg.start_addr = strtoull(tok, &endptr, 16);
+    memreg.start_addr = std::strtoull(tok, &endptr, 16);
     /* Make sure that the entire string was an hex number */
     if (*endptr != '\0')
       xbt_abort();
 
-    tok = strtok(NULL, "-");
+    tok = std::strtok(NULL, "-");
     if (tok == NULL)
       xbt_abort();
 
-    memreg.end_addr = strtoull(tok, &endptr, 16);
+    memreg.end_addr = std::strtoull(tok, &endptr, 16);
     /* Make sure that the entire string was an hex number */
     if (*endptr != '\0')
       xbt_abort();
 
     /* Get the permissions flags */
-    if (strlen(lfields[1]) < 4)
+    if (std::strlen(lfields[1]) < 4)
       xbt_abort();
 
     memreg.prot = 0;
@@ -114,13 +116,13 @@ std::vector<VmMap> get_memory_map(pid_t pid)
       memreg.flags |= MAP_SHARED;
 
     /* Get the offset value */
-    memreg.offset = strtoull(lfields[2], &endptr, 16);
+    memreg.offset = std::strtoull(lfields[2], &endptr, 16);
     /* Make sure that the entire string was an hex number */
     if (*endptr != '\0')
       xbt_abort();
 
     /* Get the device major:minor bytes */
-    tok = strtok(lfields[3], ":");
+    tok = std::strtok(lfields[3], ":");
     if (tok == NULL)
       xbt_abort();
 
@@ -129,11 +131,11 @@ std::vector<VmMap> get_memory_map(pid_t pid)
     if (*endptr != '\0')
       xbt_abort();
 
-    tok = strtok(NULL, ":");
+    tok = std::strtok(NULL, ":");
     if (tok == NULL)
       xbt_abort();
 
-    memreg.dev_minor = (char) strtoul(tok, &endptr, 16);
+    memreg.dev_minor = (char) std::strtoul(tok, &endptr, 16);
     /* Make sure that the entire string was an hex number */
     if (*endptr != '\0')
       xbt_abort();
@@ -155,8 +157,8 @@ std::vector<VmMap> get_memory_map(pid_t pid)
     ret.push_back(std::move(memreg));
   }
 
-  free(line);
-  fclose(fp);
+  std::free(line);
+  std::fclose(fp);
   return std::move(ret);
 }
 
diff --git a/src/simgrid/util.hpp b/src/simgrid/util.hpp
new file mode 100644 (file)
index 0000000..944a895
--- /dev/null
@@ -0,0 +1,38 @@
+/* Copyright (c) 2015. The SimGrid Team.
+ * All rights reserved. */
+
+#ifndef SIMGRID_UTIL_HTPP
+#define SIMGRID_UTIL_HTPP
+
+#include <algorithm>
+
+namespace simgrid {
+namespace util {
+
+/** Find a pointer to a value stores in a map (or nullptr) */
+template<typename C, typename K>
+inline
+typename C::mapped_type* find_map_ptr(C& c, K const& k)
+{
+  typename C::iterator i = c.find(k);
+  if (i == c.end())
+    return nullptr;
+  else
+    return &i->second;
+}
+
+template<typename C, typename K>
+inline
+typename C::mapped_type const* find_map_ptr(C const& c, K const& k)
+{
+  typename C::const_iterator i = c.find(k);
+  if (i == c.end())
+    return nullptr;
+  else
+    return &i->second;
+}
+
+}
+}
+
+#endif
index dab3cd5..a011a52 100644 (file)
@@ -616,8 +616,8 @@ void platf_generate(void) {
   sg_platf_host_cbarg_t host_parameters;
   sg_platf_cluster_cbarg_t cluster_parameters;
   sg_platf_link_cbarg_t link_parameters;
-  s_sg_platf_router_cbarg_t router_parameters; /* This one is not a pointer! */
-  s_sg_platf_route_cbarg_t route_parameters; /* neither this one! */
+  s_sg_platf_router_cbarg_t router_parameters = SG_PLATF_ROUTER_INITIALIZER; /* This one is not a pointer! */
+  s_sg_platf_route_cbarg_t route_parameters   = SG_PLATF_ROUTE_INITIALIZER; /* neither this one! */
 
   router_parameters.coord = NULL;
   route_parameters.symmetrical = FALSE;
index dbde952..23fd809 100644 (file)
@@ -518,7 +518,7 @@ static void elements_father(sg_routing_edge_t src, sg_routing_edge_t dst,
 static void _get_route_and_latency(RoutingEdge *src, RoutingEdge *dst,
                                    xbt_dynar_t * links, double *latency)
 {
-  s_sg_platf_route_cbarg_t route;
+  s_sg_platf_route_cbarg_t route = SG_PLATF_ROUTE_INITIALIZER;
   memset(&route,0,sizeof(route));
 
   xbt_assert(src && dst, "bad parameters for \"_get_route_latency\" method");
@@ -748,21 +748,21 @@ static void routing_parse_cabinet(sg_platf_cabinet_cbarg_t cabinet)
       surf_parse_error("Malformed radical");
       break;
     }
-    s_sg_platf_host_cbarg_t host;
+    s_sg_platf_host_cbarg_t host = SG_PLATF_HOST_INITIALIZER;
     memset(&host, 0, sizeof(host));
     host.initial_state = SURF_RESOURCE_ON;
     host.pstate        = 0;
     host.power_scale   = 1.0;
     host.core_amount   = 1;
 
-    s_sg_platf_link_cbarg_t link;
+    s_sg_platf_link_cbarg_t link = SG_PLATF_LINK_INITIALIZER;
     memset(&link, 0, sizeof(link));
     link.state     = SURF_RESOURCE_ON;
     link.policy    = SURF_LINK_FULLDUPLEX;
     link.latency   = cabinet->lat;
     link.bandwidth = cabinet->bw;
 
-    s_sg_platf_host_link_cbarg_t host_link;
+    s_sg_platf_host_link_cbarg_t host_link = SG_PLATF_HOST_LINK_INITIALIZER;
     memset(&host_link, 0, sizeof(host_link));
 
     for (i = start; i <= end; i++) {
@@ -800,8 +800,8 @@ static void routing_parse_cluster(sg_platf_cluster_cbarg_t cluster)
   xbt_dict_t patterns = NULL;
   int rankId=0;
 
-  s_sg_platf_host_cbarg_t host;
-  s_sg_platf_link_cbarg_t link;
+  s_sg_platf_host_cbarg_t host = SG_PLATF_HOST_INITIALIZER;
+  s_sg_platf_link_cbarg_t link = SG_PLATF_LINK_INITIALIZER;
 
   unsigned int iter;
   int start, end, i;
@@ -1009,7 +1009,7 @@ static void routing_parse_cluster(sg_platf_cluster_cbarg_t cluster)
   XBT_DEBUG(" ");
   XBT_DEBUG("<router id=\"%s\"/>", cluster->router_id);
   char *newid = NULL;
-  s_sg_platf_router_cbarg_t router;
+  s_sg_platf_router_cbarg_t router = SG_PLATF_ROUTER_INITIALIZER;
   memset(&router, 0, sizeof(router));
   router.id = cluster->router_id;
   router.coord = "";
@@ -1071,7 +1071,7 @@ static void routing_parse_peer(sg_platf_peer_cbarg_t peer)
   current_routing->p_linkUpDownList = xbt_dynar_new(sizeof(s_surf_parsing_link_up_down_t),NULL);
 
   XBT_DEBUG("<host\tid=\"%s\"\tpower=\"%f\"/>", host_id, peer->power);
-  s_sg_platf_host_cbarg_t host;
+  s_sg_platf_host_cbarg_t host = SG_PLATF_HOST_INITIALIZER;
   memset(&host, 0, sizeof(host));
   host.initial_state = SURF_RESOURCE_ON;
   host.id = host_id;
@@ -1087,7 +1087,7 @@ static void routing_parse_peer(sg_platf_peer_cbarg_t peer)
   host.core_amount = 1;
   sg_platf_new_host(&host);
 
-  s_sg_platf_link_cbarg_t link;
+  s_sg_platf_link_cbarg_t link = SG_PLATF_LINK_INITIALIZER;
   memset(&link, 0, sizeof(link));
   link.state   = SURF_RESOURCE_ON;
   link.policy  = SURF_LINK_SHARED;
@@ -1108,7 +1108,7 @@ static void routing_parse_peer(sg_platf_peer_cbarg_t peer)
   sg_platf_new_link(&link);
 
   XBT_DEBUG("<host_link\tid=\"%s\"\tup=\"%s\"\tdown=\"%s\" />", host_id,link_up,link_down);
-  s_sg_platf_host_link_cbarg_t host_link;
+  s_sg_platf_host_link_cbarg_t host_link = SG_PLATF_HOST_LINK_INITIALIZER;
   memset(&host_link, 0, sizeof(host_link));
   host_link.id        = host_id;
   host_link.link_up   = link_up;
@@ -1116,7 +1116,7 @@ static void routing_parse_peer(sg_platf_peer_cbarg_t peer)
   sg_platf_new_host_link(&host_link);
 
   XBT_DEBUG("<router id=\"%s\"/>", router_id);
-  s_sg_platf_router_cbarg_t router;
+  s_sg_platf_router_cbarg_t router = SG_PLATF_ROUTER_INITIALIZER;
   memset(&router, 0, sizeof(router));
   router.id = router_id;
   router.coord = peer->coord;
index 5a0dab9..c33c05f 100644 (file)
@@ -142,7 +142,7 @@ void AsCluster::getGraph(xbt_graph_t graph, xbt_dict_t nodes, xbt_dict_t edges)
 }
 
 void AsCluster::create_links_for_node(sg_platf_cluster_cbarg_t cluster, int id, int , int position){
-  s_sg_platf_link_cbarg_t link;
+  s_sg_platf_link_cbarg_t link = SG_PLATF_LINK_INITIALIZER;
   s_surf_parsing_link_up_down_t info;
   char* link_id = bprintf("%s_link_%d", cluster->id, id);
 
index fc58a79..6527e15 100644 (file)
@@ -492,7 +492,7 @@ void AsClusterFatTree::generateDotFile(const string& filename) const {
 FatTreeNode::FatTreeNode(sg_platf_cluster_cbarg_t cluster, int id, int level,
                          int position) : id(id), level(level),
                                          position(position) {
-  s_sg_platf_link_cbarg_t linkTemplate;
+  s_sg_platf_link_cbarg_t linkTemplate = SG_PLATF_LINK_INITIALIZER;
   if(cluster->limiter_link) {
     memset(&linkTemplate, 0, sizeof(linkTemplate));
     linkTemplate.bandwidth = cluster->limiter_link;
@@ -522,7 +522,7 @@ FatTreeLink::FatTreeLink(sg_platf_cluster_cbarg_t cluster,
                          FatTreeNode *upNode) : upNode(upNode),
                                                 downNode(downNode) {
   static int uniqueId = 0;
-  s_sg_platf_link_cbarg_t linkTemplate;
+  s_sg_platf_link_cbarg_t linkTemplate = SG_PLATF_LINK_INITIALIZER;
   memset(&linkTemplate, 0, sizeof(linkTemplate));
   linkTemplate.bandwidth = cluster->bw;
   linkTemplate.latency = cluster->lat;
index d6a33a5..13369b4 100644 (file)
@@ -42,7 +42,7 @@ AsClusterTorus::~AsClusterTorus()
 
 
 void AsClusterTorus::create_links_for_node(sg_platf_cluster_cbarg_t cluster, int id, int rank, int position){
-  s_sg_platf_link_cbarg_t link;
+  s_sg_platf_link_cbarg_t link = SG_PLATF_LINK_INITIALIZER;
   char* link_id;
   unsigned int j = 0;
   /**
index ba0c7cd..e10788b 100644 (file)
@@ -229,7 +229,7 @@ void STag_surfxml_storage(void)
 }
 void ETag_surfxml_storage(void)
 {
-  s_sg_platf_storage_cbarg_t storage;
+  s_sg_platf_storage_cbarg_t storage = SG_PLATF_STORAGE_INITIALIZER;
   memset(&storage,0,sizeof(storage));
 
   storage.id           = A_surfxml_storage_id;
@@ -250,7 +250,7 @@ void STag_surfxml_storage___type(void)
 }
 void ETag_surfxml_storage___type(void)
 {
-  s_sg_platf_storage_type_cbarg_t storage_type;
+  s_sg_platf_storage_type_cbarg_t storage_type = SG_PLATF_STORAGE_TYPE_INITIALIZER;
   memset(&storage_type,0,sizeof(storage_type));
 
   storage_type.content          = A_surfxml_storage___type_content;
@@ -270,7 +270,7 @@ void STag_surfxml_mstorage(void)
 }
 void ETag_surfxml_mstorage(void)
 {
-  s_sg_platf_mstorage_cbarg_t mstorage;
+  s_sg_platf_mstorage_cbarg_t mstorage = SG_PLATF_MSTORAGE_INITIALIZER;
   memset(&mstorage,0,sizeof(mstorage));
 
   mstorage.name    = A_surfxml_mstorage_name;
@@ -283,7 +283,7 @@ void STag_surfxml_mount(void)
 }
 void ETag_surfxml_mount(void)
 {
-  s_sg_platf_mount_cbarg_t mount;
+  s_sg_platf_mount_cbarg_t mount = SG_PLATF_MOUNT_INITIALIZER;
   memset(&mount,0,sizeof(mount));
 
   mount.name      = A_surfxml_mount_name;
@@ -430,7 +430,7 @@ void STag_surfxml_prop(void)
 }
 
 void ETag_surfxml_host(void)    {
-  s_sg_platf_host_cbarg_t host;
+  s_sg_platf_host_cbarg_t host = SG_PLATF_HOST_INITIALIZER;
   char* buf;
   memset(&host,0,sizeof(host));
 
@@ -484,7 +484,7 @@ void ETag_surfxml_host(void)    {
 
 void STag_surfxml_host___link(void){
   XBT_DEBUG("Create a Host_link for %s",A_surfxml_host___link_id);
-  s_sg_platf_host_link_cbarg_t host_link;
+  s_sg_platf_host_link_cbarg_t host_link = SG_PLATF_HOST_LINK_INITIALIZER;
   memset(&host_link,0,sizeof(host_link));
 
   host_link.id        = A_surfxml_host___link_id;
@@ -494,7 +494,7 @@ void STag_surfxml_host___link(void){
 }
 
 void STag_surfxml_router(void){
-  s_sg_platf_router_cbarg_t router;
+  s_sg_platf_router_cbarg_t router = SG_PLATF_ROUTER_INITIALIZER;
   memset(&router, 0, sizeof(router));
 
   router.id    = A_surfxml_router_id;
@@ -504,7 +504,7 @@ void STag_surfxml_router(void){
 }
 
 void ETag_surfxml_cluster(void){
-  s_sg_platf_cluster_cbarg_t cluster;
+  s_sg_platf_cluster_cbarg_t cluster = SG_PLATF_CLUSTER_INITIALIZER;
   memset(&cluster,0,sizeof(cluster));
   cluster.properties = as_current_property_set;
 
@@ -587,7 +587,7 @@ void STag_surfxml_cluster(void){
 
 void STag_surfxml_cabinet(void){
   parse_after_config();
-  s_sg_platf_cabinet_cbarg_t cabinet;
+  s_sg_platf_cabinet_cbarg_t cabinet = SG_PLATF_CABINET_INITIALIZER;
   memset(&cabinet,0,sizeof(cabinet));
   cabinet.id      = A_surfxml_cabinet_id;
   cabinet.prefix  = A_surfxml_cabinet_prefix;
@@ -602,7 +602,7 @@ void STag_surfxml_cabinet(void){
 
 void STag_surfxml_peer(void){
   parse_after_config();
-  s_sg_platf_peer_cbarg_t peer;
+  s_sg_platf_peer_cbarg_t peer = SG_PLATF_PEER_INITIALIZER;
   memset(&peer,0,sizeof(peer));
   peer.id                 = A_surfxml_peer_id;
   peer.power              = surf_parse_get_power(A_surfxml_peer_power);
@@ -622,7 +622,7 @@ void STag_surfxml_link(void){
 }
 
 void ETag_surfxml_link(void){
-  s_sg_platf_link_cbarg_t link;
+  s_sg_platf_link_cbarg_t link = SG_PLATF_LINK_INITIALIZER;
   memset(&link,0,sizeof(link));
 
   link.properties = current_property_set;
@@ -690,7 +690,7 @@ void STag_surfxml_link___ctn(void){
 }
 
 void ETag_surfxml_backbone(void){
-  s_sg_platf_link_cbarg_t link;
+  s_sg_platf_link_cbarg_t link = SG_PLATF_LINK_INITIALIZER;
   memset(&link,0,sizeof(link));
 
   link.properties = NULL;
@@ -743,7 +743,7 @@ void STag_surfxml_bypassASroute(void){
 }
 
 void ETag_surfxml_route(void){
-  s_sg_platf_route_cbarg_t route;
+  s_sg_platf_route_cbarg_t route = SG_PLATF_ROUTE_INITIALIZER;
   memset(&route,0,sizeof(route));
 
   route.src       = A_surfxml_route_src;
@@ -767,7 +767,7 @@ void ETag_surfxml_route(void){
 }
 
 void ETag_surfxml_ASroute(void){
-  s_sg_platf_route_cbarg_t ASroute;
+  s_sg_platf_route_cbarg_t ASroute = SG_PLATF_ROUTE_INITIALIZER;
   memset(&ASroute,0,sizeof(ASroute));
 
   ASroute.src = A_surfxml_ASroute_src;
@@ -800,7 +800,7 @@ void ETag_surfxml_ASroute(void){
 }
 
 void ETag_surfxml_bypassRoute(void){
-  s_sg_platf_route_cbarg_t route;
+  s_sg_platf_route_cbarg_t route = SG_PLATF_ROUTE_INITIALIZER;
   memset(&route,0,sizeof(route));
 
   route.src = A_surfxml_bypassRoute_src;
@@ -815,7 +815,7 @@ void ETag_surfxml_bypassRoute(void){
 }
 
 void ETag_surfxml_bypassASroute(void){
-  s_sg_platf_route_cbarg_t ASroute;
+  s_sg_platf_route_cbarg_t ASroute = SG_PLATF_ROUTE_INITIALIZER;
   memset(&ASroute,0,sizeof(ASroute));
 
   ASroute.src         = A_surfxml_bypassASroute_src;
@@ -831,7 +831,7 @@ void ETag_surfxml_bypassASroute(void){
 }
 
 void ETag_surfxml_trace(void){
-  s_sg_platf_trace_cbarg_t trace;
+  s_sg_platf_trace_cbarg_t trace = SG_PLATF_TRACE_INITIALIZER;
   memset(&trace,0,sizeof(trace));
 
   trace.id = A_surfxml_trace_id;
@@ -844,7 +844,7 @@ void ETag_surfxml_trace(void){
 
 void STag_surfxml_trace___connect(void){
   parse_after_config();
-  s_sg_platf_trace_connect_cbarg_t trace_connect;
+  s_sg_platf_trace_connect_cbarg_t trace_connect = SG_PLATF_TRACE_CONNECT_INITIALIZER;
   memset(&trace_connect,0,sizeof(trace_connect));
 
   trace_connect.element = A_surfxml_trace___connect_element;
@@ -936,7 +936,7 @@ void STag_surfxml_process(void){
 }
 
 void ETag_surfxml_process(void){
-  s_sg_platf_process_cbarg_t process;
+  s_sg_platf_process_cbarg_t process = SG_PLATF_PROCESS_INITIALIZER;
   memset(&process,0,sizeof(process));
 
   process.argc       = argc;
@@ -982,7 +982,7 @@ void STag_surfxml_gpu(void)
 }
 void ETag_surfxml_gpu(void)
 {
-  s_sg_platf_gpu_cbarg_t gpu;
+  s_sg_platf_gpu_cbarg_t gpu = SG_PLATF_GPU_INITIALIZER;
   memset(&gpu,0,sizeof(gpu));
 
   gpu.name = A_surfxml_gpu_name;
index 5c07416..4bd2e89 100644 (file)
 int test_some_array[4][5][6];
 struct some_struct { int first; int second[4][5]; } test_some_struct;
 
-static dw_type_t find_type_by_name(mc_object_info_t info, const char* name) {
-  xbt_dict_cursor_t cursor = NULL;
-  char *key;
-  dw_type_t type;
-  xbt_dict_foreach(info->types, cursor, key, type) {
-    if(!strcmp(name, type->name))
-      return type;
-  }
-
-  return NULL;
+static simgrid::mc::Type* find_type_by_name(simgrid::mc::ObjectInformation* info, const char* name)
+{
+  for (auto& entry : info->types)
+    if(entry.second.name == name)
+      return &entry.second;
+  return nullptr;
 }
 
-static dw_frame_t find_function_by_name(mc_object_info_t info, const char* name) {
-  xbt_dict_cursor_t cursor = 0;
-  dw_frame_t subprogram;
-  char* key;
-  xbt_dict_foreach(info->subprograms, cursor, key, subprogram){
-    if(!strcmp(name, subprogram->name))
-      return subprogram;
-  }
-
-  return NULL;
+static simgrid::mc::Frame* find_function_by_name(
+    simgrid::mc::ObjectInformation* info, const char* name)
+{
+  for (auto& entry : info->subprograms)
+    if(entry.second.name == name)
+      return &entry.second;
+  return nullptr;
 }
 
-static dw_variable_t find_local_variable(dw_frame_t frame, const char* argument_name) {
-  unsigned int cursor = 0;
-  dw_variable_t variable;
-  xbt_dynar_foreach(frame->variables, cursor, variable){
-    if(!strcmp(argument_name, variable->name))
-      return variable;
-  }
+static simgrid::mc::Variable* find_local_variable(
+    simgrid::mc::Frame* frame, const char* argument_name)
+{
+  for (simgrid::mc::Variable& variable : frame->variables)
+    if(argument_name == variable.name)
+      return &variable;
 
-  dw_frame_t scope = NULL;
-  xbt_dynar_foreach(frame->scopes, cursor, scope) {
-    variable = find_local_variable(scope, argument_name);
+  for (simgrid::mc::Frame& scope : frame->scopes) {
+    simgrid::mc::Variable* variable = find_local_variable(
+      &scope, argument_name);
     if(variable)
       return variable;
   }
 
-  return NULL;
+  return nullptr;
 }
 
-static void test_local_variable(mc_object_info_t info, const char* function, const char* variable, void* address, unw_cursor_t* cursor) {
-  dw_frame_t subprogram = find_function_by_name(info, function);
+static void test_local_variable(simgrid::mc::ObjectInformation* info, const char* function, const char* variable, void* address, unw_cursor_t* cursor) {
+  simgrid::mc::Frame* subprogram = find_function_by_name(info, function);
   assert(subprogram);
   // TODO, Lookup frame by IP and test against name instead
 
-  dw_variable_t var = find_local_variable(subprogram, variable);
+  simgrid::mc::Variable* var = find_local_variable(subprogram, variable);
   assert(var);
 
   void* frame_base = mc_find_frame_base(subprogram, info, cursor);
   s_mc_location_t location;
 
   mc_dwarf_resolve_locations(&location,
-    &var->locations, info, cursor, frame_base, NULL, -1);
+    &var->location_list, info, cursor, frame_base, NULL, -1);
 
   xbt_assert(mc_get_location_type(&location)==MC_LOCATION_TYPE_ADDRESS,
     "Unexpected location type for variable %s of %s", variable, function);
@@ -85,62 +77,72 @@ static void test_local_variable(mc_object_info_t info, const char* function, con
 
 }
 
-static dw_variable_t test_global_variable(mc_process_t process, mc_object_info_t info, const char* name, void* address, long byte_size) {
+static simgrid::mc::Variable* test_global_variable(simgrid::mc::Process* process, simgrid::mc::ObjectInformation* info, const char* name, void* address, long byte_size) {
 
-  dw_variable_t variable = MC_file_object_info_find_variable_by_name(info, name);
+  simgrid::mc::Variable* variable = info->find_variable(name);
   xbt_assert(variable, "Global variable %s was not found", name);
-  xbt_assert(!strcmp(variable->name, name), "Name mismatch for %s", name);
+  xbt_assert(variable->name == name,
+    "Name mismatch for %s", name);
   xbt_assert(variable->global, "Variable %s is not global", name);
   xbt_assert(variable->address == address,
-      "Address mismatch for %s : %p expected but %p found", name, address, variable->address);
+      "Address mismatch for %s : %p expected but %p found",
+      name, address, variable->address);
 
-  dw_type_t type = (dw_type_t) xbt_dict_get_or_null(process->binary_info->types, variable->type_origin);
-  xbt_assert(type!=NULL, "Missing type for %s", name);
+  auto i = process->binary_info->types.find(variable->type_id);
+  xbt_assert(i != process->binary_info->types.end(), "Missing type for %s", name);
+  simgrid::mc::Type* type = &i->second;
   xbt_assert(type->byte_size = byte_size, "Byte size mismatch for %s", name);
   return variable;
 }
 
-static dw_type_t find_member(mc_object_info_t info, const char* name, dw_type_t type) {
-  unsigned int cursor = 0;
-  dw_type_t member;
-  xbt_dynar_foreach(type->members, cursor, member){
-    if(!strcmp(name,member->name))
-      return member;
-  }
-  return NULL;
+static simgrid::mc::Type* find_member(simgrid::mc::ObjectInformation* info, const char* name, simgrid::mc::Type* type)
+{
+  for (simgrid::mc::Type& member : type->members)
+    if(member.name == name)
+      return &member;
+  return nullptr;
 }
 
 int some_local_variable = 0;
 
 typedef struct foo {int i;} s_foo;
 
-static void test_type_by_name(mc_process_t process, s_foo my_foo) {
-  assert(xbt_dict_get_or_null(process->binary_info->full_types_by_name, "struct foo"));
+static void test_type_by_name(simgrid::mc::Process* process, s_foo my_foo)
+{
+  assert(
+    process->binary_info->full_types_by_name.find("struct foo") !=
+      process->binary_info->full_types_by_name.end());
 }
 
 int main(int argc, char** argv)
 {
   SIMIX_global_init(&argc, argv);
 
-  dw_variable_t var;
-  dw_type_t type;
+  simgrid::mc::Variable* var;
+  simgrid::mc::Type* type;
 
-  s_mc_process_t p(getpid(), -1);
-  mc_process_t process = &p;
+  simgrid::mc::Process p(getpid(), -1);
+  simgrid::mc::Process* process = &p;
 
   test_global_variable(process, process->binary_info.get(),
     "some_local_variable", &some_local_variable, sizeof(int));
 
   var = test_global_variable(process, process->binary_info.get(),
     "test_some_array", &test_some_array, sizeof(test_some_array));
-  type = (dw_type_t) xbt_dict_get_or_null(process->binary_info->types, var->type_origin);
-  xbt_assert(type->element_count == 6*5*4, "element_count mismatch in test_some_array : %i / %i", type->element_count, 6*5*4);
+  auto i = process->binary_info->types.find(var->type_id);
+  xbt_assert(i != process->binary_info->types.end(), "Missing type");
+  type = &i->second;
+  xbt_assert(type->element_count == 6*5*4,
+    "element_count mismatch in test_some_array : %i / %i",
+    type->element_count, 6*5*4);
 
   var = test_global_variable(process, process->binary_info.get(),
     "test_some_struct", &test_some_struct, sizeof(test_some_struct));
-  type = (dw_type_t) xbt_dict_get_or_null(process->binary_info->types, var->type_origin);
-  assert(find_member(process->binary_info.get(), "first", type)->offset == 0);
-  assert(find_member(process->binary_info.get(), "second", type)->offset
+  i = process->binary_info->types.find(var->type_id);
+  xbt_assert(i != process->binary_info->types.end(), "Missing type");
+  type = &i->second;
+  assert(find_member(process->binary_info.get(), "first", type)->offset() == 0);
+  assert(find_member(process->binary_info.get(), "second", type)->offset()
       == ((const char*)&test_some_struct.second) - (const char*)&test_some_struct);
 
   unw_context_t context;
index fc7ab69..afd40aa 100644 (file)
@@ -15,7 +15,7 @@
 #include "../src/mc/mc_private.h"
 #include "../src/mc/mc_object_info.h"
 
-static mc_process_t process;
+static simgrid::mc::Process* process;
 
 static
 uintptr_t eval_binary_operation(mc_expression_state_t state, int op, uintptr_t a, uintptr_t b) {
@@ -119,7 +119,7 @@ int main(int argc, char** argv) {
 
   s_mc_expression_state_t state;
   memset(&state, 0, sizeof(s_mc_expression_state_t));
-  state.address_space = (mc_address_space_t) process;
+  state.address_space = (simgrid::mc::AddressSpace*) process;
 
   basic_test(&state);