/** * Handles queries for leaves. Queries of leaves are just relayed to an ultrapeer. * * @author Leo Nobach <*****@*****.**> * @version 05/06/2011 */ public class QueryHandler { Leaf owner; private Gnutella06ConnectionManager<?> mgr; static Logger log = SimLogger.getLogger(QueryHandler.class); /** * Creates the query handler for the given leaf and its connection manager mgr. * * @param owner * @param mgr */ public QueryHandler(Leaf owner, Gnutella06ConnectionManager<?> mgr) { this.owner = owner; this.mgr = mgr; } /** * Starts a query with the given query info by relaying it to an ultrapeer * * @param info */ public void startQuery(IQueryInfo info, int hitsWanted) { Query q = new Query(info); owner.getLocalEventDispatcher().queryStarted(owner.getOwnContact(), q); Gnutella06OverlayContact peerForQuery = mgr.getRandomContact(); if (peerForQuery != null) { new LeafQueryOperation(owner, q, hitsWanted, peerForQuery, this.new QueryCallback(q)) .scheduleImmediately(); } else { log.debug("Cannot start query because node " + owner.getOwnContact() + " has no ultrapeer."); } } /** Called when the leaf query was finished. */ class QueryCallback implements OperationCallback<List<QueryHit>> { private Query q; public QueryCallback(Query q) { this.q = q; } @Override public void calledOperationFailed(Operation<List<QueryHit>> op) { owner .getLocalEventDispatcher() .queryFailed(owner.getOwnContact(), q, QueryHit.getTotalHits(op.getResult())); } @Override public void calledOperationSucceeded(Operation<List<QueryHit>> op) { owner .getLocalEventDispatcher() .querySucceeded(owner.getOwnContact(), q, QueryHit.getTotalHits(op.getResult())); } } }
/** * @author <*****@*****.**> * @version 05/06/2011 */ public class KademliaAddressResolutionImpl extends AbstractAddressResolution<KademliaOverlayID, SkyNetID, KademliaOverlayKey> { private static Logger log = SimLogger.getLogger(KademliaAddressResolutionImpl.class); private static KademliaAddressResolutionImpl ari; private final Config config; private KademliaAddressResolutionImpl(int size) { config = KademliaSetup.getConfig(); byte[] bound = new byte[size + 1]; bound[0] = 1; upperBound = new BigDecimal(new BigInteger(bound)); log.debug("the upper bound of the addressSpace is " + upperBound.toPlainString()); } public static KademliaAddressResolutionImpl getInstance(int size) { if (ari == null) { ari = new KademliaAddressResolutionImpl(size); } return ari; } @Override public KademliaOverlayID getOverlayID(SkyNetID skyNetID) { BigDecimal dec = skyNetID.getID().multiply(upperBound); BigInteger kademliaOverlayID = null; try { kademliaOverlayID = dec.toBigIntegerExact(); } catch (Exception e) { log.fatal("Unable to create exact integer out of " + dec.toPlainString()); } return new KademliaOverlayID(kademliaOverlayID.subtract(BigInteger.ONE), config); } @Override public KademliaOverlayKey getOverlayKey(SkyNetID skyNetKey) { BigInteger kademliaOverlayKey = skyNetKey.getID().multiply(upperBound).toBigIntegerExact(); return new KademliaOverlayKey(kademliaOverlayKey.subtract(BigInteger.ONE), config); } @Override public SkyNetID getSkyNetID(KademliaOverlayID overlayID) { BigDecimal kademliaOverlayID = new BigDecimal(overlayID.getBigInt()).add(BigDecimal.ONE); BigDecimal skyNetID = kademliaOverlayID.divide(upperBound); return new SkyNetID(skyNetID); } }
/** * Operation listener for the CAN * * @author Bjoern Dollak <*****@*****.**> * @version February 2010 */ public class OperationListener implements OperationCallback<Object> { private CanNode master; private static Logger log = SimLogger.getLogger(CanNode.class); public OperationListener(CanNode master) { this.master = master; log.debug(Simulator.getSimulatedRealtime() + " new OperationListener"); } public void calledOperationFailed(Operation<Object> op) {} public void calledOperationSucceeded(Operation<Object> op) { // TODO Auto-generated method stub } }
/** * This class is responsible for the communication with other peers. It has methods to start a * download, upload and it receives most types of the messages from other peers. * * @author Jan Stolzenburg */ public class BTPeerDistributeNode extends AbstractOverlayNode implements TransMessageListener, DistributionStrategy { /** It stores all documents we know. */ private ContentStorage itsContentStorage; // TODO: Das bereits im Konstruktor setzen? Bisher wird es von der // Application-Klasse gesetzt. /** This class makes the handling of operations easier. */ // private BTOperationManager itsOperationManager; /** My P2P address. */ private BTContact itsOwnContact; /** This class is our interface to the network. We use it for sending and receiving messages. */ private Map<OverlayKey, BTConnectionManager> itsConnectionManagers; /** * Here we store the message handler for every torrent. The message handler handles most types of * messages that we receive from other peers. */ private Map<OverlayKey, BTMessageHandler> itsCurrentlyUploadedDocuments; // TODO: Beim beenden wieder hieraus entfernen. /** The upload operation for every torrent. */ private Collection<BTOperationUpload<BTPeerDistributeNode>> itsUploadOperations; /** The download operation for every torrent. */ private Collection<BTOperationDownload<BTPeerDistributeNode>> itsDownloadOperations; /** The statistic class stores, at which time we received how much data from every peer. */ private BTInternStatistic itsStatistic; /** A random source. */ private RandomGenerator itsRandomGenerator; /** The universal data store. We store different kind of information in it. */ private BTDataStore itsDataBus; static final Logger log = SimLogger.getLogger(BTPeerDistributeNode.class); private UC3MLogBT logger = GNP_BTSimulation_Periodical.logger; public BTPeerDistributeNode( BTDataStore theDataBus, OverlayID theOverlayID, short thePeerDistributionPort, BTInternStatistic theStatistic, RandomGenerator theRandomGenerator) { super(theOverlayID, thePeerDistributionPort); this.itsDataBus = theDataBus; this.itsStatistic = theStatistic; this.itsRandomGenerator = theRandomGenerator; this.itsConnectionManagers = new HashMap<OverlayKey, BTConnectionManager>(); this.itsCurrentlyUploadedDocuments = new HashMap<OverlayKey, BTMessageHandler>(); this.itsDownloadOperations = new LinkedList<BTOperationDownload<BTPeerDistributeNode>>(); this.itsUploadOperations = new LinkedList<BTOperationUpload<BTPeerDistributeNode>>(); } /** * This method starts a download by creating and activating a download operation. * * @param theOverlayKey the key/hash of the document that we want to download. * @param theOtherPeers a list of peers start also participate in this torrent. We normaly get * this list from the tracker. * @return the operation id of the started download operation. */ public int downloadDocument( OverlayKey theOverlayKey, List<TransInfo> theOtherPeers, OperationCallback theCallback) { log.debug( "Time: " + Simulator.getCurrentTime() + "; Starting download at '" + this.itsOwnContact + "'."); BTDocument document; BTConnectionManager connectionManager; if (!this.itsContentStorage.containsDocument(theOverlayKey)) { document = new BTDocument( theOverlayKey, ((BTTorrent) this.itsDataBus.getPerTorrentData(theOverlayKey, "Torrent")).getSize()); this.itsContentStorage.storeDocument(document); } else { document = (BTDocument) this.itsContentStorage.loadDocument(theOverlayKey); } if (!this.itsConnectionManagers.containsKey(theOverlayKey)) { connectionManager = new BTConnectionManager(this.itsOwnContact); this.itsConnectionManagers.put(theOverlayKey, connectionManager); } else { connectionManager = this.itsConnectionManagers.get(theOverlayKey); } BTOperationDownload<BTPeerDistributeNode> downloadOperation = new BTOperationDownload<BTPeerDistributeNode>( this.itsDataBus, document, this.itsOwnContact, this, this, connectionManager, this.itsStatistic, this.itsRandomGenerator); this.itsDownloadOperations.add(downloadOperation); downloadOperation.scheduleImmediately(); return downloadOperation.getOperationID(); } /** * This method starts a upload by creating and activating a download operation. * * @param theOverlayKey the key/hash of the document that we want to upload. * @return the operation id of the started upload operation. */ public int uploadDocument(OverlayKey theOverlayKey, OperationCallback theCallback) { log.debug("Starting upload at '" + this.itsOwnContact + "'."); BTDocument document; BTConnectionManager connectionManager; if (!this.itsContentStorage.containsDocument(theOverlayKey)) { throw new RuntimeException("You tried to upload an unknown document."); } else { document = (BTDocument) this.itsContentStorage.loadDocument(theOverlayKey); } if (!this.itsConnectionManagers.containsKey(theOverlayKey)) { connectionManager = new BTConnectionManager(this.itsOwnContact); this.itsConnectionManagers.put(theOverlayKey, connectionManager); } else { connectionManager = this.itsConnectionManagers.get(theOverlayKey); } BTOperationUpload<BTPeerDistributeNode> uploadOperation = new BTOperationUpload<BTPeerDistributeNode>( this.itsDataBus, document, this.itsOwnContact, this, this, connectionManager, this.itsStatistic, this.itsRandomGenerator); this.itsUploadOperations.add(uploadOperation); uploadOperation.scheduleImmediately(); if (!this.itsCurrentlyUploadedDocuments.containsKey(theOverlayKey)) { this.itsCurrentlyUploadedDocuments.put( theOverlayKey, new BTMessageHandler( this.itsDataBus, document, this.itsOwnContact, uploadOperation, this.getTransLayer(), connectionManager)); } return uploadOperation.getOperationID(); } public void setContentStorage(ContentStorage theContentStorage) { this.itsContentStorage = theContentStorage; } /** * Most types of P2P messages in BitTorrent are no direct replies. They are all received by this * method. It casts them to a subtype and forwards them to the message handler. * * @param theMessageEvent the message event that is received. */ public void messageArrived(TransMsgEvent theMessageEvent) { Message theMessage = theMessageEvent.getPayload(); if (!(theMessage instanceof BTMessage)) { String errorMessage = "Received a non-BitTorrent message: '" + theMessage.toString() + "'"; log.error(errorMessage); throw new RuntimeException(errorMessage); } BTMessage theBTMessage = (BTMessage) theMessage; BTContact theOtherPeer = new BTContact(theBTMessage.getSender(), theMessageEvent.getSenderTransInfo()); // A table lookup for the message type would be better than this case statement. But this is // much to much overhead in Java, as we don't have first class functions. // TODO: Aufr�umen, so dass man nicht jedes mal das gleiche macht. Am besten nur nachschauen von // wem die Nachricht ist, nachschlagen in welchem Torrent dieser Peer ist und fertig. switch (theBTMessage.getType()) { case REQUEST: { BTPeerMessageRequest theRequest = (BTPeerMessageRequest) theBTMessage; OverlayKey theDocument = theRequest.getRequest().getOverlayKey(); if (!this.itsCurrentlyUploadedDocuments.containsKey(theDocument)) { // We just ignore this message. log.warn( "Received an unexpected request from '" + theOtherPeer + "' for '" + theDocument + "'!"); return; } if (this.itsConnectionManagers.get(theDocument).getConnection(theOtherPeer) != null) this.itsConnectionManagers .get(theDocument) .getConnection(theOtherPeer) .receivedMessage(theRequest); this.itsCurrentlyUploadedDocuments .get(theDocument) .handleRequestMessage(theRequest, theOtherPeer, theMessageEvent); return; } case CANCEL: { BTPeerMessageCancel theCancelMessage = (BTPeerMessageCancel) theBTMessage; OverlayKey theDocument = theCancelMessage.getOverlayKey(); if (!this.itsCurrentlyUploadedDocuments.containsKey(theCancelMessage.getOverlayKey())) { // We just ignore this message. log.warn( "Received an unexpected cancel message from '" + theOtherPeer + "' for '" + theCancelMessage.getOverlayKey() + "'!"); return; } if (this.itsConnectionManagers.get(theDocument).getConnection(theOtherPeer) != null) this.itsConnectionManagers .get(theDocument) .getConnection(theOtherPeer) .receivedMessage(theCancelMessage); this.itsCurrentlyUploadedDocuments .get(theCancelMessage.getOverlayKey()) .handleCancelMessage(theCancelMessage, theOtherPeer); return; } case HAVE: { BTPeerMessageHave theHaveMessage = (BTPeerMessageHave) theBTMessage; OverlayKey theDocument = theHaveMessage.getOverlayKey(); if (!this.itsCurrentlyUploadedDocuments.containsKey(theHaveMessage.getOverlayKey())) { // We just ignore this message. log.warn( "Received an unexpected have message from '" + theOtherPeer + "' for '" + theHaveMessage.getOverlayKey() + "'!"); return; } if (this.itsConnectionManagers.get(theDocument).getConnection(theOtherPeer) != null) this.itsConnectionManagers .get(theDocument) .getConnection(theOtherPeer) .receivedMessage(theHaveMessage); this.itsCurrentlyUploadedDocuments .get(theHaveMessage.getOverlayKey()) .handleHaveMessage(theHaveMessage, theOtherPeer); return; } case HANDSHAKE: { BTPeerMessageHandshake theHandshake = (BTPeerMessageHandshake) theBTMessage; OverlayKey theDocument = theHandshake.getOverlayKey(); if (!this.itsCurrentlyUploadedDocuments.containsKey(theHandshake.getOverlayKey())) { // We just ignore this message. log.debug( "Received an unexpected handshake at '" + this.itsOwnContact.getOverlayID() + "' from '" + theOtherPeer.getOverlayID() + "' for '" + theHandshake.getOverlayKey() + "'!"); return; } if (this.itsConnectionManagers.get(theDocument).getConnection(theOtherPeer) != null) this.itsConnectionManagers .get(theDocument) .getConnection(theOtherPeer) .receivedMessage(theHandshake); this.itsCurrentlyUploadedDocuments .get(theHandshake.getOverlayKey()) .handleHandshakeMessage(theHandshake, theOtherPeer); return; } case BITFIELD: { BTPeerMessageBitField theBitfield = (BTPeerMessageBitField) theBTMessage; OverlayKey theDocument = theBitfield.getOverlayKey(); if (!this.itsCurrentlyUploadedDocuments.containsKey(theBitfield.getOverlayKey())) { // We just ignore this message. log.warn( "Received an unexpected bitfield from '" + theOtherPeer + "' for '" + theBitfield.getOverlayKey() + "'!"); return; } if (this.itsConnectionManagers.get(theDocument).getConnection(theOtherPeer) != null) this.itsConnectionManagers .get(theDocument) .getConnection(theOtherPeer) .receivedMessage(theBitfield); this.itsCurrentlyUploadedDocuments .get(theBitfield.getOverlayKey()) .handleBitfieldMessage(theBitfield, theOtherPeer); return; } case INTERESTED: { BTPeerMessageInterested theInterestMessage = (BTPeerMessageInterested) theBTMessage; OverlayKey theDocument = theInterestMessage.getOverlayKey(); if (!this.itsCurrentlyUploadedDocuments.containsKey(theInterestMessage.getOverlayKey())) { // We just ignore this message. log.warn( "Received an unexpected interest message from '" + theOtherPeer + "' for '" + theInterestMessage.getOverlayKey() + "'!"); return; } if (this.itsConnectionManagers.get(theDocument).getConnection(theOtherPeer) != null) this.itsConnectionManagers .get(theDocument) .getConnection(theOtherPeer) .receivedMessage(theInterestMessage); this.itsCurrentlyUploadedDocuments .get(theInterestMessage.getOverlayKey()) .handleInterestMessage(theInterestMessage, theOtherPeer); return; } case UNINTERESTED: { BTPeerMessageUninterested theUninterestMessage = (BTPeerMessageUninterested) theBTMessage; OverlayKey theDocument = theUninterestMessage.getOverlayKey(); if (!this.itsCurrentlyUploadedDocuments.containsKey( theUninterestMessage.getOverlayKey())) { // We just ignore this message. log.warn( "Received an unexpected uninterest message from '" + theOtherPeer + "' for '" + theUninterestMessage.getOverlayKey() + "'!"); return; } if (this.itsConnectionManagers.get(theDocument).getConnection(theOtherPeer) != null) this.itsConnectionManagers .get(theDocument) .getConnection(theOtherPeer) .receivedMessage(theUninterestMessage); this.itsCurrentlyUploadedDocuments .get(theUninterestMessage.getOverlayKey()) .handleUninterestMessage(theUninterestMessage, theOtherPeer); return; } case CHOKE: { BTPeerMessageChoke theChokeMessage = (BTPeerMessageChoke) theBTMessage; OverlayKey theDocument = theChokeMessage.getOverlayKey(); if (!this.itsCurrentlyUploadedDocuments.containsKey(theChokeMessage.getOverlayKey())) { // We just ignore this message. log.warn( "Received an unexpected choke message from '" + theOtherPeer + "' for '" + theChokeMessage.getOverlayKey() + "'!"); return; } if (this.itsConnectionManagers.get(theDocument).getConnection(theOtherPeer) != null) this.itsConnectionManagers .get(theDocument) .getConnection(theOtherPeer) .receivedMessage(theChokeMessage); this.itsCurrentlyUploadedDocuments .get(theChokeMessage.getOverlayKey()) .handleChokeMessage(theChokeMessage, theOtherPeer); return; } case UNCHOKE: { BTPeerMessageUnchoke theUnchokeMessage = (BTPeerMessageUnchoke) theBTMessage; OverlayKey theDocument = theUnchokeMessage.getOverlayKey(); if (!this.itsCurrentlyUploadedDocuments.containsKey(theUnchokeMessage.getOverlayKey())) { // We just ignore this message. log.warn( "Received an unexpected unchoke message from '" + theOtherPeer + "' for '" + theUnchokeMessage.getOverlayKey() + "'!"); return; } if (this.itsConnectionManagers.get(theDocument).getConnection(theOtherPeer) != null) this.itsConnectionManagers .get(theDocument) .getConnection(theOtherPeer) .receivedMessage(theUnchokeMessage); this.itsCurrentlyUploadedDocuments .get(theUnchokeMessage.getOverlayKey()) .handleUnchokeMessage(theUnchokeMessage, theOtherPeer); return; } case KEEPALIVE: { BTPeerMessageKeepAlive theKeepAliveMessage = (BTPeerMessageKeepAlive) theBTMessage; OverlayKey theDocument = theKeepAliveMessage.getOverlayKey(); if (!this.itsCurrentlyUploadedDocuments.containsKey( theKeepAliveMessage.getOverlayKey())) { // We just ignore this message. log.warn( "Received an unexpected keep alive message from '" + theOtherPeer + "' for '" + theKeepAliveMessage.getOverlayKey() + "'!"); return; } if (this.itsConnectionManagers.get(theDocument).getConnection(theOtherPeer) != null) this.itsConnectionManagers .get(theDocument) .getConnection(theOtherPeer) .receivedMessage(theKeepAliveMessage); this.itsCurrentlyUploadedDocuments .get(theKeepAliveMessage.getOverlayKey()) .handleKeepAliveMessage(theOtherPeer); return; } case PIECE: { // BTPeerMessagePiece thePieceMessage = (BTPeerMessagePiece) theBTMessage; /* * I wasn't able to find the reason for these failures: * It seams that the requests themselves get sometimes delayed and arrive much to late. * But this failure accures also, if the requests are not delayed. * There are not nearly-late piece messages: Either they arrive within some seconds or they are too late. (> 180 sec.) * But nothing in between... */ // log.warn("Received an piece-message that has timed out! It needed '" + // ((BTUtil.getTime() - thePieceMessage.getTimestamp()) / BTUtil.getSecond()) + "' seconds // till the answer of the request arrived."); // log.warn("Received an piece-message that has timed out! Size: '" + // thePieceMessage.getMessageSize() + "'; it needed '" + ((BTUtil.getTime() - // thePieceMessage.getTimestamp()) / BTUtil.getSecond()) + "' seconds; it needed '" + // ((BTUtil.getTime() - thePieceMessage.getRequestTime()) / BTUtil.getSecond()) + "' // seconds till the answer of the request arrived. Piece: '" + // thePieceMessage.getPieceNumber() + "'; Block: '" + thePieceMessage.getBlockNumber() + // "';"); return; } default: { String errorMessage = "Received an unknown BitTorrent message: '" + theBTMessage.toString() + "'"; log.error(errorMessage); throw new RuntimeException(errorMessage); } } } @Override public TransLayer getTransLayer() { return this.getHost().getTransLayer(); } public TransInfo getTransInfo() { return this.itsOwnContact.getTransInfo(); } public void connect() { this.getTransLayer().addTransMsgListener(this, this.getPort()); this.itsContentStorage = this.getHost().getStorage(); this.itsOwnContact = new BTContact(this.getOverlayID(), this.getTransLayer().getLocalTransInfo(this.getPort())); } public Operation createOperation(String opName, String[] params, OperationCallback caller) { // TODO Auto-generated method stub throw new RuntimeException( "Method 'createOperation' in class 'BTPeerDistributeNode' not yet implemented!"); // return null; } public void connectivityChanged(ConnectivityEvent ce) { // TODO Auto-generated method stub throw new RuntimeException( "Method 'connectivityChanged' in class 'BTPeerDistributeNode' not yet implemented!"); // } @Override public void calledOperationFailed(Operation op) { if (op instanceof BTOperationDownload) { logger.process( this.getClass().toString(), new Object[] {op, new Long(Simulator.getCurrentTime()), new Boolean(false)}); } } @Override public void calledOperationSucceeded(Operation opd) { if (opd instanceof BTOperationDownload) { BTOperationDownload op = (BTOperationDownload) opd; logger.process( this.getClass().toString(), new Object[] {op, new Long(op.getFinishedTime()), new Boolean(true)}); } } }
/** * Concrete implementation of a simulator which can be used to run a simulation by calling the main * method in the SimulatorRunner class. * * @author Sebastian Kaune * @author Konstantin Pussep * @version 3.0, 11/29/2007 */ public class Simulator implements Configurable { private static final Logger log = SimLogger.getLogger(Simulator.class); /** These constant should be ALWAYS used for virtual time calculations. */ // public final static long MICROSECOND_UNIT = 1l; /** These constant should be ALWAYS used for virtual time calculations. */ public static final long MILLISECOND_UNIT = 1000l; // * MICROSECOND_UNIT; /** These constant should be ALWAYS used for virtual time calculations. */ public static final long SECOND_UNIT = 1000l * MILLISECOND_UNIT; /** These constant should be ALWAYS used for virtual time calculations. */ public static final long MINUTE_UNIT = 60l * SECOND_UNIT; /** These constant should be ALWAYS used for virtual time calculations. */ public static final long HOUR_UNIT = 60l * MINUTE_UNIT; /** Scenario holding all the information about the current simulation run. */ private Scenario scenario; /** Singleton instance of default simulator. */ private static Simulator singleton; /** Configurator instance is used to initialize the scenario. */ private DefaultConfigurator defaultConfigurator; private boolean running; private static long seed; private static Scheduler scheduler; private static RandomGenerator randomGen = new JDKRandomGenerator(); private static Monitor monitor; private static boolean finishedWithoutError = false; /** This class is singleton, so use getInstance() method to obtain a reference to it. */ private Simulator() { singleton = this; scheduler = new Scheduler(true); monitor = new DefaultMonitor(); } /** * Returns the single instance of the SimulationFramework * * @return the SimulationFramework */ public static Simulator getInstance() { if (singleton == null) singleton = new Simulator(); return singleton; } /** * Set the scenario (protocol stack, network topology etc.) which will be used to run the * simulation. * * @param scenario simulation scenario to be used */ public void setScenario(Scenario scenario) { checkRunning(); this.scenario = scenario; } /** This method will run the simulation using the previously set scenario data. */ public void start() { checkRunning(); log.info("Prepare Scenario ..."); this.scenario.prepare(); log.info("Running Scenario with seed=" + getSeed()); long startTime = System.currentTimeMillis(); log.info("Simulation started..."); this.running = true; try { scheduler.start(); finishedWithoutError = true; } catch (Exception e) { log.error("Simulator run stopped because of error", e); finishedWithoutError = false; } finally { this.running = false; } log.info("Simulation finished."); long runTime = System.currentTimeMillis() - startTime; long minutes = (long) Math.floor((runTime) / 60000); long secs = (runTime % 60000) / 1000; log.info("Realtime Duration of experiment (m:s) " + minutes + ":" + secs); log.info("Simulated time is " + getSimulatedRealtime()); } /** * Configure simulation from an XML file. * * @param configFile XML file with the configuration data. * @param variables the variables which are specified in the XML file with the configuarion data. */ public void configure(String configFile, Map<String, String> variables) { this.defaultConfigurator = new DefaultConfigurator(configFile); defaultConfigurator.setVariables(variables); this.defaultConfigurator.register(Configurator.CORE, this); Collection<Configurable> components = this.defaultConfigurator.configureAll(); log.debug("components " + components); ScenarioFactory scenarioBuilder = (ScenarioFactory) this.defaultConfigurator.getConfigurable(Configurator.SCENARIO_TAG); if (scenarioBuilder == null) throw new ConfigurationException( "No scenario builder specified in the configuration file. Nothing to do."); Scenario scenario = scenarioBuilder.createScenario(); setScenario(scenario); } /** * Returns the seed used within a simulation run. * * @return the predefined seed */ public static long getSeed() { return seed; } /** * This method sets the seed of the global random generator which can be obtained using the static * getRandom()-method. * * @param seed the seed to configure the global random generator */ public void setSeed(long seed) { checkRunning(); this.seed = seed; randomGen.setSeed(seed); } /** * Returns the global monitor which can be used to delegate information/occured events to a * specific analyzer/s. * * @return the global monitor */ public static Monitor getMonitor() { if (monitor == null) monitor = new DefaultMonitor(); return monitor; } /** Assure that the set methods are not called after the simulation has started. */ private void checkRunning() { if (this.running) throw new IllegalStateException("Simulator is already running."); } /** * This method provides the global random generator which has to be used within the simulation * framework to generate reproducable results depending on a predefined seed. * * @return the global random generator with a predefined seed. */ public static RandomGenerator getRandom() { return randomGen; } /** * Sets the monitor which has to be configured by using the XML file with the configuration data. * * @param monitor monitor predefined in the XML file with the configuration data. */ public void setMonitor(Monitor monitor) { checkRunning(); this.monitor = monitor; } /** * Returns the current simulation unit value. * * @return the current simulation unit value */ public static long getCurrentTime() { return scheduler.getCurrentTime(); } /** * Returns the simulated realtime in the format (Hours:Minutes:Seconds). * * @return the simulated realtime */ public static String getSimulatedRealtime() { return scheduler.getSimulatedRealtime(); } /** * Inserts new event in queue * * @param content the content of the event * @param simulationTime time to schedule the event * @param handler handler which will receive this event * @param eventType specific simulation event */ public static void scheduleEvent( Object content, long simulationTime, SimulationEventHandler handler, SimulationEvent.Type eventType) { scheduler.scheduleEvent(content, simulationTime, handler, eventType); } /** * Reset the simulator, so that it can be configured again for another simulation run without to * restart the Java Virtual Machine. This is especially usefull for JUnit tests. */ void reset() { checkRunning(); // TODO may be there should be default values for some of them monitor = new DefaultMonitor(); scenario = null; scheduler = new Scheduler(true); seed = 0; } static Scheduler getScheduler() { return scheduler; } /** * Sets the end time at which the simulation framework will finish at the latest the simulation , * irrespective if there are still unprocessed events in the event queue. * * @param endTime point in time at which the simular will finish at the latest */ public void setFinishAt(long endTime) { checkRunning(); this.scheduler.setFinishAt(endTime); } static boolean isFinishedWithoutError() { return finishedWithoutError; } /** * Can be used to format the absolute simulation time (current, past or future) into * human-readable format: (h:m:s:ms). * * @param time - absolute simulation time like the one obtained via getCurrentTime(); * @return human-readable representation of the given simulation time */ public static String getFormattedTime(long time) { return scheduler.getFormattedTime(time); } /** * Specifies how often the scheduler will printout the current simulation time. * * @param time */ public void setStatusInterval(long time) { scheduler.setStatusInterval(time); } }
/** * This class is used to periodically start random lookup request * * @author Minh Hoang Nguyen <*****@*****.**> * @version 05/06/2011 */ public class LookupGenerator implements Configurable { private static Logger log = SimLogger.getLogger(LookupGenerator.class); protected static ArrayList<Integer> lookupList = new ArrayList<Integer>(); /** * [0] : sum of lookup [1] : failed/loss lookup [2] : receive reply lookup [3] : correct lookup */ protected static int[] lookupCount = new int[4]; public void startRandomLookup(ChordNode starter) { log.debug("lookup counter " + Arrays.toString(lookupCount)); lookupCount[0]++; long randomLong = Simulator.getRandom().nextLong(); String token = Long.toString(Math.abs(randomLong), 32); ChordID key = ChordIDFactory.getInstance().getChordID(token); int lookupID = starter.overlayNodeLookup(key, new MyCallback()); log.debug("started lookup request key = " + key + " id = " + lookupID + " from = " + starter); lookupList.add(lookupID); } public void setStart(long start) { new LookupBegin().scheduleWithDelay(start); } class MyCallback implements OperationCallback<List<ChordContact>> { @Override public void calledOperationFailed(Operation op) { // do nothing lookupCount[1]++; } @Override public void calledOperationSucceeded(Operation op) { // do nothing lookupCount[2]++; LookupOperation lookupOp = (LookupOperation) op; Integer lookup = new Integer(lookupOp.getLookupId()); lookupList.remove(lookup); log.trace("unfinished lookup " + Arrays.toString(lookupList.toArray())); ChordID target = lookupOp.getTarget(); ChordID result = lookupOp.getResult().get(0).getOverlayID(); if (ChordConfiguration.DO_CHORD_EVALUATION) analyzeLookupResult(target, result); } } protected void analyzeLookupResult(ChordID target, ChordID result) { ChordNode responder = ChordOverlayUtil.getResponsibleNode( ChordBootstrapManager.getInstance(target).getAvailableNodes(), target.getValue()); boolean valid = responder.getOverlayID().equals(result); if (!valid) { log.error( "incorrect lookup result" + " key = " + target + " correct responder " + responder + " found = " + result); } else { // +1 correct lookup lookupCount[3]++; } } public static boolean containLookupId(int lookupId) { return lookupList.contains(lookupId); } }
/** * This operation sends a PingMsg to a neighbour and awaits a response. If no response arrives it is * tried CanConfig.numberPings times. If their is still no response, it tries to finds which peer * has the most common parents with the missing node. This peer gets a takeover message which starts * the TakeoverRabuild Operation. If the actual node is the has the most common vid parents, it * starts the TakeoverRebuildOperation itself. So it send a takeoverReorganizeMsg to every node * which has the same number of vid parents. If missing node and actual node are leafs of the tree, * the actual node just takes the area and adds it to its own. * * @author Bjoern Dollak <*****@*****.**> * @version February 2010 */ public class TakeoverReplyOperation extends AbstractOperation<CanNode, Object> { private static final Logger log = SimLogger.getLogger(CanNode.class); private CanNode node; private CanOverlayContact neighbour; private boolean succ, delete; private int allreadyTried; private TakeoverOperation takeoverOperation; private boolean otherAnswer; /** * starts a TakeoverReplyOperation in this node for one of its neighbours * * @param component CanNode which should check its neighbours * @param neighbour neighbour to check * @param takeoverOperation this operation called the TekeoverReply Operation */ public TakeoverReplyOperation( CanNode component, CanOverlayContact neighbour, TakeoverOperation takeoverOperation) { super(component); this.node = getComponent(); this.neighbour = neighbour; this.takeoverOperation = takeoverOperation; this.allreadyTried = 0; this.succ = false; this.delete = false; otherAnswer = false; } @Override public void execute() { if (node.getPeerStatus() == PeerStatus.PRESENT && delete == false && node.neighboursContain(neighbour)) { if (allreadyTried < CanConfig.numberPings && succ == false) { PingMsg ping = new PingMsg( node.getLocalContact().getOverlayID(), neighbour.getOverlayID(), node.getLocalContact().clone()); ping.setOperationId(this.getOperationID()); node.getTransLayer() .send(ping, neighbour.getTransInfo(), node.getPort(), TransProtocol.UDP); allreadyTried++; this.operationFinished(true); this.scheduleWithDelay(CanConfig.timeout); } else if (allreadyTried >= CanConfig.numberPings && succ == false && otherAnswer == false) { this.operationFinished(true); this.scheduleWithDelay(CanConfig.numberPings * CanConfig.timeout + 2 * CanConfig.timeout); } else if (allreadyTried >= CanConfig.numberPings && succ == false) { log.warn( Simulator.getSimulatedRealtime() + " node left, own id: " + node.getLocalContact().getOverlayID().toString() + " " + node.getLocalContact().getArea().toString() + " missing node: " + neighbour.getOverlayID().toString() + " " + neighbour.getArea().toString() + " " + this.getOperationID()); for (CanOverlayContact neighbour : node.getNeighbours()) { log.warn("own neighbours: " + neighbour.getOverlayID().toString()); } CanOverlayContact closestVidNeighbour = null; if (neighbour .getArea() .getVid() .getVIDList() .get(neighbour.getArea().getVid().getVIDList().size() - 1) .equals("0")) closestVidNeighbour = node.getVidNeighboursOfCertainNeighbour(neighbour)[1]; else closestVidNeighbour = node.getVidNeighboursOfCertainNeighbour(neighbour)[0]; if (closestVidNeighbour != null) { // ////////////normaly used // without the case, not // well tested log.debug( "closest vid neighbour: " + closestVidNeighbour.getOverlayID().toString() + " in node " + node.getLocalContact().getOverlayID().toString() + " " + neighbour.getArea().getVid().toString() + " " + node.getLocalContact().getArea().getVid().toString() + " " + neighbour .getArea() .getVid() .closestNeighbour(node.getLocalContact().getArea().getVid())); // controll if one of the neighbours is the direct neighbour if (neighbour .getArea() .getVid() .closestNeighbour(node.getLocalContact().getArea().getVid())) { log.debug( "direct Vid neighbour is missing " + " neighbour " + neighbour.getArea().getVid().toString() + " own " + node.getLocalContact().getArea().getVid().toString() + " " + neighbour .getArea() .getVid() .closestNeighbour(node.getLocalContact().getArea().getVid())); if (node.getMissingNode() == null) { node.setMissingNode(neighbour); TakeoverRebuildOperation takeoverRebuildOperation = new TakeoverRebuildOperation(node); takeoverRebuildOperation.scheduleWithDelay(CanConfig.waitForTakeover); this.operationFinished(true); } } // own node is closest, but not brother else if (closestVidNeighbour .getOverlayID() .toString() .equals(node.getLocalContact().getOverlayID().toString()) && (node.getVIDNeighbours()[0] .getOverlayID() .toString() .equals(neighbour.getOverlayID().toString()) || node.getVIDNeighbours()[1] .getOverlayID() .toString() .equals(neighbour.getOverlayID().toString()))) { if (node.getMissingNode() == null) { node.setMissingNode(neighbour); CanOverlayContact n = null; if (node.getVIDNeighbours()[0] .getArea() .getVid() .equals(neighbour.getArea().getVid())) n = node.getVIDNeighbours()[1]; else n = node.getVIDNeighbours()[0]; TakeoverReorganizeMsg leave = new TakeoverReorganizeMsg( (CanOverlayID) node.getOverlayID(), n.getOverlayID(), node.getLocalContact().clone(), neighbour); node.getTransLayer().send(leave, n.getTransInfo(), node.getPort(), TransProtocol.TCP); TakeoverRebuildOperation takeoverRebuildOperation = new TakeoverRebuildOperation(node); takeoverRebuildOperation.scheduleWithDelay(CanConfig.waitForTakeover); this.operationFinished(true); } else log.debug("node is allready set"); } else { // send takeoverMsg CanOverlayContact receiver = null; if (closestVidNeighbour.getArea().getVid().numberCommon(neighbour.getArea().getVid()) >= node.getLocalContact() .getArea() .getVid() .numberCommon(neighbour.getArea().getVid())) receiver = closestVidNeighbour; else if (neighbour .getArea() .getVid() .getVIDList() .get(neighbour.getArea().getVid().getVIDList().size() - 1) .toString() .equals("0")) receiver = node.getVIDNeighbours()[0]; else receiver = node.getVIDNeighbours()[1]; log.debug( "send takeovermsg from " + node.getLocalContact().getOverlayID().toString() + " to " + receiver.getOverlayID().toString()); List<CanOverlayContact> neighboursOfMissing = node.getNeighboursOfCertainNeighbour(neighbour); CanOverlayContact[] vidNeighboursOfMissing = node.getVidNeighboursOfCertainNeighbour(neighbour); TakeoverMsg takeoverMsg = new TakeoverMsg( node.getLocalContact().getOverlayID(), receiver.getOverlayID(), neighbour, neighboursOfMissing, vidNeighboursOfMissing); node.getTransLayer() .send(takeoverMsg, receiver.getTransInfo(), node.getPort(), TransProtocol.TCP); log.debug( "missing node detected and just removed, in node: " + node.getLocalContact().getOverlayID().toString() + " missing node: " + neighbour.getOverlayID().toString()); node.removeNeighbour(neighbour); this.takeoverOperation.takeoverReplyFinished(this.getOperationID()); } } else { log.debug( "missing node detected and just removed, in node: " + node.getLocalContact().getOverlayID().toString() + " missing node: " + neighbour.getOverlayID().toString()); node.removeNeighbour(neighbour); this.takeoverOperation.takeoverReplyFinished(this.getOperationID()); } } else { this.takeoverOperation.takeoverReplyFinished(this.getOperationID()); this.operationFinished(true); } } } public Object getResult() { return null; } public void found(PongMsg msg) { succ = true; } public void deleteOperation() { delete = true; } public boolean getSucc() { return succ; } public void anotherAnswer() { otherAnswer = true; } public void updateNode(CanNode node) { this.node = node; } }
/** * @author <*****@*****.**> * @version 05/06/2011 */ public class Quadrant { private static final Logger log = SimLogger.getLogger(Quadrant.class); private HashMap<MobileNetID, MobileNetLayer> NodeList; /** Constructor for a new quadrant */ public Quadrant() { this.NodeList = new HashMap<MobileNetID, MobileNetLayer>(); } /** * Adds a node to this quadrant * * @param id : MobileNetId * @param p * @return True: if added successfully. */ public void addNode(MobileNetID id, MobileNetLayer p) { NodeList.put(id, p); } /** * Delete this node from this quadrant * * @param id * @return Boolean */ public boolean deleteNode(MobileNetID id) { MobileNetLayer temp = NodeList.remove(id); if (temp == null) return false; else return true; } public void deleteNode(LinkedList<MobileNetLayer> list) { for (Iterator<MobileNetLayer> iterator = list.iterator(); iterator.hasNext(); ) { MobileNetLayer t1 = iterator.next(); NodeList.remove(t1.getNetID()); } } /** @return How many nodes are present in this quadrant */ public int getNodeCount() { return NodeList.size(); } /** * Execute the method "moveNode" for all nodes which are present in this network. If the node has * moved out of this quadrant, add it to a list and return it to the manager. * * @param last_changed : Time to calculate the distance for. Current time minus the last update * time * @return LinkedList: List with all the nodes, which have been moved out of the array and were * already deleted. */ public LinkedList<MobileNetLayer> updateMovement() { LinkedList<MobileNetLayer> l = new LinkedList<MobileNetLayer>(); for (Map.Entry<MobileNetID, MobileNetLayer> e : NodeList.entrySet()) { MobileNetLayer elem = e.getValue(); MobileNode n = (MobileNode) e.getValue().getNetPosition(); double x = n.getXPos(); double y = n.getYPos(); n.updateMovement(); // If the node moved out of my quadrant, add it to the returned List // and remove it from my list if ((x != n.getXPos()) || (y != n.getYPos())) { l.add(elem); } } this.deleteNode(l); return l; } public void outputNodes() { for (Map.Entry<MobileNetID, MobileNetLayer> e : NodeList.entrySet()) { MobileNode n = (MobileNode) e.getValue().getNetPosition(); double x = n.getXPos(); double y = n.getYPos(); if (x == 0.8151173344625606D) log.debug(e.getKey() + ";" + x + ";" + y); } } public HashMap<MobileNetID, MobileNetLayer> getNodes() { return NodeList; } public boolean contains(NetID netID) { return NodeList.containsKey(netID); } }
/** * Implementing a centralized DHT overlay, whose organization of the centralized index is similar to * the distributed index of Chord * * @author Dominik Stingl <*****@*****.**> * @version 1.0, 08.12.2008 */ public class ClientLeaveOperation extends AbstractOperation<NapsterClientNode, Object> implements TransMessageCallback { private static Logger log = SimLogger.getLogger(ClientLeaveOperation.class); private ClientLeaveRequestMsg request = null; private ClientLeaveReplyMsg reply; private int msgID = -2; public ClientLeaveOperation(NapsterClientNode component, OperationCallback<Object> callback) { super(component, callback); NapsterOverlayID ownOID = getComponent().getOwnOverlayID(); if (getComponent().getServerOverlayContact() != null && getComponent().getServerOverlayContact().getOverlayID() != null) { NapsterOverlayID serverOID = getComponent().getServerOverlayContact().getOverlayID(); request = new ClientLeaveRequestMsg(ownOID, serverOID, null, getOperationID()); } } @Override protected void execute() { if (request == null) return; TransInfo serverTransInfo = getComponent().getServerOverlayContact().getTransInfo(); msgID = getComponent() .getTransLayer() .sendAndWait( request, serverTransInfo, getComponent().getPort(), TransProtocol.TCP, this, 10 * Simulator.SECOND_UNIT); log.info("[Client] Initiating transMessage with id " + msgID + "-->opID " + getOperationID()); } @Override public Object getResult() { // No result needed return null; } public void messageTimeoutOccured(int commId) { log.info("[Client] Message-timeout of transMessage with ID = " + commId + " occured"); operationFinished(false); } public void receive(Message msg, TransInfo senderInfo, int commId) { reply = (ClientLeaveReplyMsg) msg; if (request.getOpID() == reply.getOpID()) { log.info("[Client] transMessage with ID = " + commId + " is received"); operationFinished(true); } else { log.error("The opID send does not equal the opID received"); } } }
/** * This builder will parse an XML subtree and create hosts as specified there. It expects a tree * which looks as follows: <code> * <HostBuilder> * <Host groupID="...">... * <Group size="..." groupID="...">... * <HostBuilder/> * </code> The exact values for XML tags are specified as constants in this class (see below). * * @author Konstantin Pussep <*****@*****.**> * @author Sebastian Kaune * @version 3.0, 29.11.2007 */ public class DefaultHostBuilder implements HostBuilder, Composable, Builder { /** XML attribute with this name specifies the size of the group. */ public static final String GROUP_SIZE_TAG = "size"; /** XML element with this name specifies a group of hosts. */ public static final String GROUP_TAG = "Group"; /** * XML element with this name specifies a single host and behaves equivalent to an element with * the name = GROUP_TAG value and group size of 1. */ public static final String HOST_TAG = "Host"; /** * XML attribute with this name specifies the id of the group, which is used to refer to this * group lateron, e.g. when you specify scenario actions. */ public static final String GROUP_ID_TAG = "groupID"; private static final Logger log = SimLogger.getLogger(DefaultHostBuilder.class); /** Groups of hosts indexed by group ids. */ protected Map<String, List<Host>> groups; protected int experimentSize; /** Flat list of all hosts. */ protected final List<Host> hosts = new LinkedList<Host>(); /** * Will be called by the configurator. * * @param size total number of hosts in the simulator TODO we could remove this or force its * correctness... */ public void setExperimentSize(int size) { groups = new HashMap<String, List<Host>>(size); this.experimentSize = size; } public void compose(Configurator config) { // unused } /* * (non-Javadoc) * * @see de.tud.kom.p2psim.api.scenario.HostBuilder#getAllHostsWithGroupIDs() */ public Map<String, List<Host>> getAllHostsWithGroupIDs() { Map<String, List<Host>> hosts = new HashMap<String, List<Host>>(groups); return hosts; } /* * (non-Javadoc) * * @see de.tud.kom.p2psim.api.scenario.HostBuilder#getAllHosts() */ public List<Host> getAllHosts() { return hosts; } /* * (non-Javadoc) * * @see * de.tud.kom.p2psim.api.scenario.HostBuilder#getHosts(java.lang.String) */ public List<Host> getHosts(String groupId) { return groups.get(groupId); } /* * (non-Javadoc) * * @see de.tud.kom.p2psim.api.scenario.HostBuilder#parse(org.dom4j.Element, * de.tud.kom.p2psim.api.scenario.Configurator) */ public void parse(Element elem, Configurator config) { DefaultConfigurator defaultConfigurator = (DefaultConfigurator) config; // create groups for (Iterator iter = elem.elementIterator(); iter.hasNext(); ) { Element groupElem = (Element) iter.next(); String groupID = groupElem.attributeValue(GROUP_ID_TAG); if (groupID == null) { throw new IllegalArgumentException( "Id of host/group " + groupElem.asXML() + " must not be null"); } // either a group of hosts or a single host (=group with size 1) int groupSize; if (groupElem.getName().equals(HOST_TAG)) { groupSize = 1; } else if (groupElem.getName().equals(GROUP_TAG)) { String attributeValue = config.parseValue(groupElem.attributeValue(GROUP_SIZE_TAG)); groupSize = Integer.parseInt(attributeValue); } else { throw new IllegalArgumentException("Unexpected tag " + groupElem.getName()); } List<Host> group = new ArrayList<Host>(groupSize); // create hosts and instances of specified components for each host for (int i = 0; i < groupSize; i++) { DefaultHost host = new DefaultHost(); // initialize properties DefaultHostProperties hostProperties = new DefaultHostProperties(); host.setProperties(hostProperties); // minimal information for host properties is the group id hostProperties.setGroupID(groupID); // initialize layers and properties for (Iterator layers = groupElem.elementIterator(); layers.hasNext(); ) { Element layerElem = (Element) layers.next(); if (layerElem.getName().equals(Configurator.HOST_PROPERTIES_TAG)) { defaultConfigurator.configureAttributes(hostProperties, layerElem); } else { // layer component factory ComponentFactory layer = (ComponentFactory) defaultConfigurator.configureComponent(layerElem); Component comp = layer.createComponent(host); setComponent(host, comp); } } group.add(host); } log.debug("Created a group with " + group.size() + " hosts"); hosts.addAll(group); groups.put(groupID, group); } log.info("CREATED " + hosts.size() + " hosts"); if (hosts.size() != experimentSize) { log.warn( "Only " + hosts.size() + " hosts were specified, though the experiment size was set to " + experimentSize); } } protected void setComponent(DefaultHost host, Component comp) { // TODO setComponent method in the host? if (comp instanceof NetLayer) { host.setNetwork((NetLayer) comp); } else if (comp instanceof TransLayer) { host.setTransport((TransLayer) comp); } else if (comp instanceof OverlayNode) { host.setOverlayNode((OverlayNode) comp); } else if (comp instanceof Application) { host.setApplication((Application) comp); } else if (comp instanceof ContentStorage) { host.setContentStorage((DefaultContentStorage) comp); } } }