Beispiel #1
0
 def runOU(self, nSlots, TTL):
     Log.pLD(self, "Executing OU Algorithm for {0}".format(nSlots) )
     #print("[{0}] peers [ {1} ]".format(self.pid, self._peersConn))
    
     #t = SSimulator().tick
     chosen = list()
    
     #Calculate the number of current OU Slots and possible candidates that are interested but not in OU or TFT
     candidates = self.getOUCandidates()
     if(len(candidates) < nSlots):
         self._getMorePeersFlag = True
         nSlots = len(candidates)
         if(nSlots == 0):
             return chosen
     
     candidates = random.sample(candidates, len(candidates)) #Array of peerId
     
     while( len(chosen) < nSlots ):
         p = candidates.pop(0)
         
         #Only unchok peers that are not already unchoked!
         if( (p[4] != self.OU_SLOT) ):
             self._peersConn[p[1]][2].unchock()    
         
         self._peersConn[p[1]] = ( p[0], p[1], p[2], TTL, self.OU_SLOT )
         chosen.append(p[1])
         
     #Do chocking of all OU peers that currently are unchoked but not have been chosen in this round
     for p in self._peersConn.values():
         if( (p[4] == self.OU_SLOT) and (chosen.count(p[1]) == 0) ):
             self._peersConn[p[1]] = ( p[0], p[1], p[2], -1, self.NO_SLOT )
             self._peersConn[p[1]][2].chock()
             
     self._nOUSlots = len(chosen) 
     return chosen
Beispiel #2
0
    def updateLocalConnectionState(self):   
        self._activeDownloadBandwidthUsage = 0

        if(self._leaveNextRound == True):
            self._torrent.tracker.remPeer(self)
            self._disconnectConnections()
            self.removeSimElement()
            Log.pLI(self, "Leaving torrent ...")
            
        if self._torrent.isFinished() == True :
            if( self._downloadEnd == -1):
                self._downloadEnd = SSimulator().tick
            #So check if we want to leave or stay as a seeder
            if( self._leaveTorrent() == True ):
                self._leaveNextRound = True #Leave next round, if not, the peer wont be seen by the observer as finished!
        else:
            if( (SSimulator().tick >= self._nextPieceQueueUpdate)  or (len(self.piecesQueue) == 0) ):
                Log.pLD(self, "Getting new piece list for downloading ..." )
                (self.piecesQueue, self._pieceAvailability) = self.pieceSelection(self._pieceRandomizeCount) #Simulates the queuing of piece requests to other peers
                self._nextPieceQueueUpdate = SSimulator().tick + 5 #Shedule next update
        
        #Call updateLocalState() on each connection and update their averageDownloadRate
        finishedPieces = self._torrent.getFinishedPieces()
        for i in self._peersConn.values() :
            i[2].updateLocalState(finishedPieces)            
Beispiel #3
0
    def getNewPeerList(self):
        
        #Dont create too many connections to other peers ( because of performance problems )        
        if(len(self._peersConn) >= self._maxPeerListSize):
            return
        t = SSimulator().tick
        if( (t - self._lastPeerListUpdate) < self._timeBetweenPeerListUpdates):
            return
        else:
            self._lastPeerListUpdate = t
        
        Log.pLD(self, "Ask Tracker for new peers ...".format())
        newPeers = self._torrent.tracker.getPeerList()

        #Filter unwanted peers , for example itself
        def f(x): return ( x.pid != self.pid )
        newPeers = filter( f, newPeers )

        for i in newPeers :
            if (i.pid in self._peersConn) == False:
                newConnection = Connection(self, i)
                self._peersConn[i.pid] = ( 0, i.pid, newConnection, -1 , self.NO_SLOT )
                newConnection.setUploadLimit( self._calculateUploadRate(newConnection) )
                #newConnection.setDownloadLimit( self._calculateDownloadRate(newConnection) )
                newConnection.connect()
                Log.pLD(self, "adding Peer [{0}]".format(i.pid))
Beispiel #4
0
 def _dropPeers(self, maxPeers):
     p = list(self._peersConn)
     nDrop = len(p) - maxPeers
     if(nDrop < 0):
         return #Nothing to do
     
     while(nDrop > 0 and len(p) > 0):
         pID = random.sample(p, 1)[0]
         #print("Dropping peer {} from {}".format(pID, p))
         p.remove(pID)
             
         c = self._peersConn[pID]
         if(c[2].interested == True):
             continue #Do not drop peers we are interested in
         
         if(c[2].peerIsInterested() == True):
             continue #Do not drop peers that have interest in our data
         
         if(c[4] != Peer.NO_SLOT):
             continue #Do not drop active connection of any kind
        
         if(c[2].getDownloadRate() > 0):
             continue #Do not drop peers we are downloading from
         
         Log.pLD(self, "Dropping peer [{}]".format( c[1]) )
         self._peersConn[pID][2].disconnect()
         nDrop-=1
Beispiel #5
0
 def unchock(self, uploadRate=-1):
     if(uploadRate > -1):
         self._maxUploadRate = int(uploadRate)
     #if(downloadRate > -1):
     #    self._maxDownloadRate = int(downloadRate)
     self.chocking = False
     Log.pLD(self._srcPeer, "unchocking [{0}@{1}]".format(self._destPeer.pid, self._maxUploadRate) )
     self.__calculateUploadRate()
Beispiel #6
0
    def runSeederOU(self, nRepeatingSlots, nRandomSlots, TTL):
        Log.pLD(self, "Executing Seeder OU Algorithm for {} reapting, and {} ramdon Slots".format(nRepeatingSlots, nRandomSlots) )
       
        #t = SSimulator().tick
        chosen = list()
       
        #Calculate the number of current OU Slots and possible candidates that are interested but not in OU or TFT
        candidates = self.getOUCandidates()
        if(len(candidates) == 0):
            return chosen
        
        #Shuffle candidates to select nRandomSlots really random
        random.shuffle(candidates)
        
        candidates2 = list(candidates)
        
        #Get nRepeatingSlots; Only peers that we are already uploading data to!
        while( (len(chosen) <  nRepeatingSlots) and (len(candidates) > 0) ):
            p = candidates.pop(0)
                       
            #Only get already OU allocated ones
            if( (p[4] != self.OU_SLOT) ):
                continue

            #Skip un interested ones
            if( p[2].peerIsInterested() == False):
                continue 
            
            self._peersConn[p[1]] = ( p[0], p[1], p[2], TTL, self.OU_SLOT )
            chosen.append(p[1])

        #No randomly select nRandomSlots more ( or if we could not select enough nRepeatingSlots, select a random one too )
        candidates = candidates2          
        while( (len(chosen) <  nRepeatingSlots+nRandomSlots) and (len(candidates) > 0) ):
            p = candidates.pop(0)
            
            if(p in chosen):
                continue
            
            #Only unchok peers that are not already unchoked!
            if( (p[4] != self.OU_SLOT) ):
                self._peersConn[p[1]][2].unchock()    
            
            self._peersConn[p[1]] = ( p[0], p[1], p[2], TTL, self.OU_SLOT )
            chosen.append(p[1])
            
        #Do chocking of all OU peers that currently are unchoked but not have been chosen in this round
        for p in self._peersConn.values():
            if( (p[4] == self.OU_SLOT) and (chosen.count(p[1]) == 0) ):
                self._peersConn[p[1]] = ( p[0], p[1], p[2], -1, self.NO_SLOT )
                self._peersConn[p[1]][2].chock()
                
        self._nOUSlots = len(chosen) 
        return chosen
Beispiel #7
0
 def connectToPeer(self, peer):
     #logging.log(Simulator.DEBUG, "[{0}] External peer is connecting! [{1}]".format(self.pid, peer.pid))
     Log.pLD(self, "External peer is connecting! [{0}]".format(peer.pid) )
     newConnection = None
         
     #If we already now this peer, return current connection
     if peer.pid in self._peersConn :
         newConnection = self._peersConn[peer.pid][2]
     else:
         Log.pLD(self, "adding Peer [{0}]".format(peer.pid)) 
         newConnection = Connection(self, peer)
         self._peersConn[peer.pid] = ( 0, peer.pid, newConnection, -1 , self.NO_SLOT)
         newConnection.setUploadLimit( self._calculateUploadRate(newConnection) )
         #newConnection.setDownloadLimit( self._calculateDownloadRate(newConnection) )
         self._peersConn[peer.pid][2].connect()
     
     #Return the connection reference
     return newConnection
Beispiel #8
0
    def runTFT(self, nSlots, TTL):
        Log.pLD(self, " Executing TFT Algorithm for {0}".format(nSlots) )
        #self._peersConn.sort() #Peer list in the form ( <UploadRate>, <PeerID>, <Connection> ) , sort will on the first field and on collision continue with the others
        
        #t = SSimulator().tick
        chosen = list()
        
        #Now everyone is a candidate, take even current OU Slots, this makes sense to step up a peer from OU to TFT is they are good
        candidates = self.getTFTCandidates()
        
        if(len(candidates) == 0):
            self._getMorePeersFlag = True
            #return chosen #DO NOT RETURN HERE OR THE CHOCKING AT THE END OF THE FUNCTION WONT BE APPLIED
        
        candidates.sort(reverse=True) #Sort candidates based on their uploadRate, (highest uploadRate first)

        shuffledFlag = False
        while( (len(chosen) < nSlots) and (len(candidates) > 0) ):
            p = candidates.pop(0)
            
            #If all the rest of the peers have zero upload, shuffle them
            if((p[0] == 0) and (shuffledFlag == False)):
                shuffledFlag = True #Only shuffle once
                candidates.append(p)
                candidates = random.sample(candidates, len(candidates)) #Array of peerId
                p = candidates.pop(0)
            
            #Only unchok peers that are not already unchoked!
            if( (p[4] != self.TFT_SLOT) ):
                self._peersConn[p[1]][2].unchock()    
            
            self._peersConn[p[1]] = ( p[0], p[1], p[2], TTL, self.TFT_SLOT )
            chosen.append(p[1])
        
        #Do chocking of all TFT peers that currently are unchocked but not have been chosen in this round
        for p in self._peersConn.values():
            if( (p[4] == self.TFT_SLOT) and (chosen.count(p[1]) == 0) ):
                self._peersConn[p[1]] = ( p[0], p[1], p[2], -1, self.NO_SLOT )
                self._peersConn[p[1]][2].chock()
   
        self._nTFTSlots = len(chosen)
        return chosen
Beispiel #9
0
    def updateGlobalState(self):

        if( self.disconnected == True ):
            #Connection was disconnected, tell peer
            self._srcPeer.peerDisconnect(self)
            return

        #Check if we are seeding , if so, we are __NEVER__ interested
        if(self._srcPeer.getTorrent().isFinished() == False):
        
            #Check what the other peer has to offer
            self._downloadablePieces = self.__calcDownloadablePieceSet()        
            if(len(self._downloadablePieces) > 0):
                Log.pLD(self._srcPeer, "Having interest in {0} from {1}".format( len(self._downloadablePieces), self._destPeer.pid) )
                self.interested = True
                self.__setCurrentPiece()
                #if( self.chocking == True ):
                #    self.unchock(self._uploadRate, 0)
            else:
                Log.pLD(self._srcPeer, "Loosing interest in peer {0}".format(self._destPeer.pid) )
                #self.chocking = True
                self.interested = False
        else:
            self.interested = False
Beispiel #10
0
    def _wakeUpPeer(self):
        
        if( self._sleepTime > 0):
            self._sleepTime -= 1
            return
        
        Log.pLD(self, "Node waking up ...".format())
        
        #Unregister sleep and setup peer for normal operation
        self.unregisterSimFunction(Simulator.ST_INIT, self._wakeUpPeer )
        
        self.registerSimFunction(Simulator.ST_UPDATE_LOCAL, self.updateLocalConnectionState )
        self.registerSimFunction(Simulator.ST_UPDATE_GLOBAL, self.updateGlobalConnectionState )
        self.registerSimFunction(Simulator.ST_LOGIC, self.peerLogic )
        self.registerSimFunction(Simulator.ST_FILETRANSFER, self._runDownloads )
        self.registerSimFunction(Simulator.ST_CONCLUTION, self._conclusionState )

        #Decide when to run tft and ou algorithm next time
        self._nextTFTPhaseStart = SSimulator().tick
        self._nextOUPhaseStart = SSimulator().tick
        self._nextPieceQueueUpdate = SSimulator().tick
        
        #Register to tracker
        self._torrent.tracker.connect(self)
Beispiel #11
0
    def runDownload(self):
        #If nothing happens, nothing is downloaded
        self._downloadRate = 0
        
        #Downloading happens if we are interested and the other peer is not chocking us
        if( (self.interested == True) and (self.remoteConnection.chocking == False) ):

            #Limit maximum download rate
            currentDownloadRate = self.remoteConnection.getUploadRate()
            currentDownloadRate = self._srcPeer.requestDownloadBandwidth(currentDownloadRate)
            #if(currentDownloadRate > self._maxDownloadRate):
            #    currentDownloadRate = self._maxDownloadRate

            #Check if we finished a complete piece and if so mark it as finished and get the next one
            self._acumulatedData += currentDownloadRate
           
            self._downloadRate = currentDownloadRate
            
            #Make this int so we dont get too long floating number in output log
            self._downloadRate = int(self._downloadRate)
            
            Log.pLD(self._srcPeer, "Downloaded {0}/{1} of piece {2}".format(self._acumulatedData, self._srcPeer.getTorrent().pieceSizeBytes, self._currentPiece) )
            while(self._acumulatedData > self._srcPeer.getTorrent().pieceSizeBytes):
                Log.pLD(self._srcPeer, "Finished downloading piece {0}".format(self._currentPiece) )
            
                self._srcPeer.finishedDownloadingPiece(self, self._currentPiece )
                self._acumulatedData -= self._srcPeer.getTorrent().pieceSizeBytes
                self._currentPiece = -1
                #Set a next piece and utilize the data downloaded for this one. If there are no more pieces discard the downloaded data
                if(self.__setCurrentPiece() == False):
                    self._acumulatedData = 0   #This is simulating lost bandwidth due to running out of piece requests
                    Log.pLD(self._srcPeer, "Piece request queue empty!" )
                    #On start of next round we will loose interest
                    #self.interested = False
            
            if(self._currentPiece == -1):
                self.__setCurrentPiece()
Beispiel #12
0
 def chock(self):
     self.chocking = True
     self._uploadRate = 0
     Log.pLD(self._srcPeer, "chocking [{0}]".format(self._destPeer.pid) )
Beispiel #13
0
 def __del__(self):
     Log.pLD("Peer is being destroyed")
Beispiel #14
0
    def runTFT(self, nSlots, TTL):
        
        candidates = self.getTFTCandidates()
        if len(candidates) == 0:
            self._getMorePeersFlag = True
            #return list() #DO NOT RETURN HERE OR THE CHOCKING AT THE END OF THE FUNCTION WONT BE APPLIED
        
        #Create a list of tuples, or peer rating and peer id
        #Rate peers depending on their download/upload ration. New peers get a ration of zero (worst) , maybe change this to one?
        rated = []
        for (idx,i) in enumerate(candidates) :
            if( i[2].getUploadLimit() == 0):
                rated.append( (0, idx) )
            else:
                rated.append( (i[0] / i[2].getUploadLimit() , idx) )

        rated.sort(reverse=True)
        rated2 = list(rated) #Copy the rated list for later
       
        chosen = []
         
        #This will be set earlier by self._calculateSlotCountAndUploadRate()
        maxUpload = self._maxTFTUploadRate
        acUploadRate = 0

        #nSlots = min(nSlots, len(rated))
        while( (acUploadRate < maxUpload ) and (len(chosen) < nSlots) and (len(rated) > 0) ):
            idx = rated.pop(0)[1] #Index of the elements in candidates
            p = candidates[idx] 
            
            #Skip peers that would take too much upload
            if( (acUploadRate + p[2].getUploadLimit()) > maxUpload ):
                continue
            
            #Only unchok peers that are not already unchocked!
            if(p[4] != self.TFT_SLOT):
                self._peersConn[p[1]][2].unchock()
            
            self._peersConn[p[1]] = ( p[0],p[1],p[2], TTL , self.TFT_SLOT )
            chosen.append(p[1])
            acUploadRate += p[2].getUploadLimit()
        
        #If we are not able to use all our upload capacity something is wrong. Do more peer discovery -> get more peers
        restOfUploadBandwidth = maxUpload - acUploadRate
        if(restOfUploadBandwidth>100):
            self._getMorePeersFlag = True
            #Take another peer and limit the upload to the available bandwidth
            rated = rated2
            while( (acUploadRate < maxUpload ) and (len(chosen) < nSlots) and (len(rated) > 0) ):
                idx = rated.pop()[1] #Index of the elements in candidates
                p = candidates[idx] 
                    
                #Skip peers that would take too much upload
                if( p[1] in chosen ):
                    continue
                
                #Only unchok peers that are not already unchocked!
                if(p[4] != self.TFT_SLOT):
                    self._peersConn[p[1]][2].unchock()
                
                p[2].setUploadLimit(restOfUploadBandwidth)#Important
                
                self._peersConn[p[1]] = ( p[0],p[1],p[2], TTL , self.TFT_SLOT )
                chosen.append(p[1])
                acUploadRate += p[2].getUploadLimit()
                
        #Do chocking of all TFT peers that currently are unchocked but not have been chosen in this round
        for i in self._peersConn.values():
            if( (i[4] == self.TFT_SLOT) and (chosen.count(i[1]) == 0) ):
                self._peersConn[i[1]] = ( i[0], i[1], i[2], -1, self.NO_SLOT )
                self._peersConn[i[1]][2].chock()
        
        Log.pLD(self, " Executed modified TFT Algorithm and selected {0} peers".format( len(chosen) ) )
        self._nTFTSlots = len(chosen)
        
        return chosen
Beispiel #15
0
    def _runOU(self, nSlots, TTL):
        Log.pLD(self, "Executing OU Algorithm for {0}".format(nSlots) )
        #print("[{0}] peers [ {1} ]".format(self.pid, self._peersConn))
       
        #t = SSimulator().tick
        chosen = list()
       
        #Calculate the number of current OU Slots and possible candidates that are interested but not in OU or TFT
        candidates = self.getOUCandidates()
        if(len(candidates) < nSlots):
            self._getMorePeersFlag = True
            nSlots = len(candidates)
            #if(nSlots == 0):
            #    return chosen
            #DO NOT RETURN HERE OR THE CHOCKING AT THE END OF THE FUNCTION WONT BE APPLIED
        
        random.shuffle(candidates)
        candidates2 = list(candidates)
        
        while( (len(chosen) < nSlots) and (len(candidates) > 0) ):
            p = candidates.pop(0)
            
            #Prefer interested peers
            if( p[2].peerIsInterested() == False):
                continue

            #Only unchok peers that are not already unchoked!
            if( (p[4] != self.OU_SLOT) ):
                self._peersConn[p[1]][2].unchock()    
            
            self._peersConn[p[1]] = ( p[0], p[1], p[2], TTL, self.OU_SLOT )
            chosen.append(p[1])
        
        #If there are not enough interested peers, take some random peers
        if(len(chosen) < nSlots):
            self._getMorePeersFlag = True #Do more/better peer discovery
            candidates = candidates2
            while( (len(chosen) < nSlots) and (len(candidates) > 0) ):
                p = candidates.pop(0)
                
                #Dont add peers twice
                if( (p[1] in chosen) == True):
                    continue
    
                #Only unchok peers that are not already unchoked!
                if( (p[4] != self.OU_SLOT) ):
                    self._peersConn[p[1]][2].unchock()    
                
                self._peersConn[p[1]] = ( p[0], p[1], p[2], TTL, self.OU_SLOT )
                chosen.append(p[1])

        
        #Do chocking of all OU peers that currently are unchoked but not have been chosen in this round
        for p in self._peersConn.values():
            if( (p[4] == self.OU_SLOT) and (chosen.count(p[1]) == 0) ):
                self._peersConn[p[1]] = ( p[0], p[1], p[2], -1, self.NO_SLOT )
                self._peersConn[p[1]][2].chock()
                
        self._nOUSlots = len(chosen)
        if(self._nOUSlots < nSlots):
            pass
        return chosen