Beispiel #1
0
    def isCloser(self, peerB, targetPosition):
        """ Return True if this peer is closer than peerB to targetPosition
        """
        d1 = Geometry.distance(self.getPosition(), targetPosition)
        d2 = Geometry.distance(peerB.getPosition(), targetPosition)

        return d1 < d2
Beispiel #2
0
    def getPeerAround(self, targetPosition, emitter_id, isClockWise=True):
        """ Return the peer that is the closest to a target position and that
        is in the right half plane.
        targetPosition : target position which we are looking around
        isClockWise : boolean indicating if we we searching in the right or the
        left half-plane - optional
        Return : a peer or None if there is no peer in the half plane
        """
        found = False
        around = None
        distClosest = 0
        nodePosition = self.node.getPosition()
        for p in self.peers.values():
            if p.getId() == emitter_id:
                continue
            if Geometry.inHalfPlane(nodePosition, targetPosition,
                                    p.getPosition()) == isClockWise:
                # first entity in right half-plane
                if not found:
                    found = True
                    around = p
                    distClosest = Geometry.distance(targetPosition, p.getPosition())
                else:
                    dist = Geometry.distance(targetPosition, p.getPosition())
                    # this peer is closer
                    if dist < distClosest:
                        around = p
                        distClosest = dist

        return around
Beispiel #3
0
    def NEAREST(self, event):
        """ While scanning around our target a position, a peer informs us that
        there exists a peer that is closer than our current best.
        """
        peerPos = event.getArg(protocol.ARG_REMOTE_POSITION)

        # check if this peer is closer than our current best
        currentBestDistance = Geometry.distance(self.best.getPosition(),
                                                self.node.getPosition())
        newDist = Geometry.distance(peerPos, self.node.getPosition())
        if newDist < currentBestDistance:
            super(Scanning,self).NEAREST(event)
            self.node.setState(Locating())
Beispiel #4
0
    def getBadGlobalConnectivityPeers(self):
        """ Check if global connectivity is ensured

        Return a pair of entities not respecting property or an empty set.
        First entity should be used to search clockwise and the second one ccw"""
        result = []

        nodePos = self.node.getPosition()
        length = self.getNumberOfPeers()

        if length == 0:
            return []

        if length == 1:
            (peer,) = self.peers.values()
            return [peer, peer]

        for index in range(length):
            ent = self.ccwPeers.ll[index]
            nextEnt = self.ccwPeers.ll[ (index+1) % length ]
            entPos = ent.getPosition()
            nextEntPos = nextEnt.getPosition()
            if not Geometry.inHalfPlane(entPos, nodePos, nextEntPos):
                return [ent, nextEnt]
        return []
Beispiel #5
0
    def BEST(self, event):
        """ A peer sent us a BEST message
        This is the default behaviour
        """
        # unexpected message, do not process it
        msg = 'BEST'
        if not self.isExpected(msg):
            self.logger.debug('Error, reception of a ' + msg + 'message in state '
                              + str(self.__class__))
            return

        self.timer.cancel()

        # Get the ID and the position of the BEST peer
        bestId = event.getArg(protocol.ARG_ID)
        bestPos = event.getArg(protocol.ARG_POSITION)
        bestAddress = event.getSenderAddress()

        # send a queryaround message
        bestDistance = Geometry.distance(self.node.getPosition(), bestPos)
        factory = EventFactory.getInstance(PeerEvent.TYPE)
        queryaround = factory.createQUERYAROUND(bestId, bestDistance)
        queryaround.setRecipientAddress(bestAddress)
        self.node.dispatch(queryaround)

        # Create a turning state and store the Best peer
        bestPeer = Peer(id=bestId, address=event.getSenderAddress(),
                        position=bestPos)
        scanning = Scanning()
        scanning.setBestPeer(bestPeer)

        # go to the Scanning state
        self.node.setState(scanning)
Beispiel #6
0
    def QUERYAROUND(self, event):
        """ A peer sent us a QUERYAROUND message """
        #peer, idNearest, distNearest:
        source_id = event.getArg(protocol.ARG_ID)
        idNearest = event.getArg(protocol.ARG_BEST_ID)
        distNearest = event.getArg(protocol.ARG_BEST_DISTANCE)
        manager = self.node.getPeersManager()
        target = event.getArg(protocol.ARG_POSITION)
        closest = manager.getClosestPeer(target, source_id)

        factory = EventFactory.getInstance(PeerEvent.TYPE)
        # found a closest peer and this peer is a new one (it isn't idNearest moving
        # toward target position).
        if ( (Geometry.distance(closest.getPosition(), target) < distNearest) and
             closest.getId() <> idNearest ):
            # send a nearest message
            nearestEvent = factory.createNEAREST(closest)
            nearestEvent.setRecipientAddress(event.getSenderAddress())
            self.node.dispatch(nearestEvent)

        else:
            # search for a peer around target position
            around = manager.getPeerAround(target, source_id)
            if around is not None:
                aroundEvt = factory.createAROUND(around)
                aroundEvt.setRecipientAddress(event.getSenderAddress())
                self.node.dispatch(aroundEvt)
            else:
                self.logger.debug('no peer around position: ' + str(target))
Beispiel #7
0
 def computeAwarenessRadius(self):
     """ Based on curent the repartition of our peers (number, position),
     compute what should be our awareness radius
     Return an awareness radius (integer)
     """
     if self.hasTooManyPeers():
         offset = self.getNumberOfPeers() - self.maxPeers
         # get the awareness radius of the last peer that is inside our AR
         # in distance order
         index = len(self.distPeers) - offset -1
         return self.distPeers.ll[index].getAwarenessRadius()
     elif self.hasTooFewPeers():
         fartherPeerPos = self.distPeers.ll[len(self.distPeers) - 1].getPosition()
         maxDist = Geometry.distance(self.node.getPosition(), fartherPeerPos)
         density = maxDist / self.getNumberOfPeers()
         return self.expectedPeers / density
     else:
         fartherPeerPos = self.distPeers.ll[len(self.distPeers) - 1].getPosition()
         return Geometry.distance(self.node.getPosition(), fartherPeerPos)
Beispiel #8
0
    def getWorstPeers(self):
        """ Return a list of peers with which we should disconnect. Removing these
        peers must NOT break the global connectivity rule.
        Return a list of peers or [] if we cannot remove a peer
        """
        if not self.hasTooManyPeers():
            return []

        # filter list of neighbors
        # keep only entities not in Awareness Area which do not provoke mis-respect
        # of Global Connectivity Rule

        FilterList = []
        endFilter = True
        indexFilter = len(self.distPeers) - 1
        nodePos = self.node.getPosition()

        while endFilter and indexFilter > 0:
            ent = self.distPeers.ll[indexFilter]
            distEnt = Geometry.distance(ent.getPosition(), nodePos)

            # first, verify that ent is not in Awareness Area
            if distEnt > self.node.getAwarenessRadius() :
                # and that we are not in its AR
                if distEnt > ent.getAwarenessRadius():

                    indInCcw = self.ccwPeers.ll.index(ent)
                    successor = self.ccwPeers.ll[(indInCcw + 1) % len(self.ccwPeers)]
                    predecessor = self.ccwPeers.ll[indInCcw - 1]

                    # then verify that ent is not mandatory for Rule respect
                    if Geometry.inHalfPlane(predecessor.getPosition(), nodePos,
                                            successor.getPosition()):
                        FilterList.append(ent)

            else:
                # stop iteration because all following entities are in Awareness
                # Radius
                endFilter = False

            indexFilter -= 1

        return FilterList
Beispiel #9
0
 def computeAwarenessRadius(self):
     """ Based on curent the repartition of our peers (number, position),
     compute what should be our awareness radius
     Return an awareness radius (integer)
     """
     if self.hasTooManyPeers():
         offset = self.getNumberOfPeers() - self.maxPeers
         index = len(self.distPeers) - offset - 1
         # Get the average between the max inside distance and the min outside distance
         pos_outside = self.distPeers.ll[index].getPosition()
         pos_inside = self.distPeers.ll[index - 1].getPosition()
         dist_outside = Geometry.distance(self.node.getPosition(), pos_outside)
         dist_inside = Geometry.distance(self.node.getPosition(), pos_inside)
         return (dist_outside + dist_inside) // 2
     if self.hasTooFewPeers():
         fartherPeerPos = self.distPeers.ll[len(self.distPeers) - 1].getPosition()
         maxDist = Geometry.distance(self.node.getPosition(), fartherPeerPos)
         # Areal density
         return maxDist * math.sqrt(self.expectedPeers / self.getNumberOfPeers())
     else:
         fartherPeerPos = self.distPeers.ll[len(self.distPeers) - 1].getPosition()
         return Geometry.distance(self.node.getPosition(), fartherPeerPos)
Beispiel #10
0
    def necessaryPeers(self):
        """ Returns the list of peers that are necessary for our global connectivity. """

        n = len(self.ccwPeers)
        if n < 4:
            return self.enumeratePeers()
        result = []
        for i in xrange(n):
            pred_pos = self.ccwPeers.ll[i - 2].getPosition()
            pos = self.node.getPosition()
            succ_pos = self.ccwPeers.ll[i].getPosition()
            if not Geometry.inHalfPlane(pred_pos, pos, succ_pos):
                result.append(self.ccwPeers.ll[i - 1])

        return result
Beispiel #11
0
    def AROUND(self, event):
        """ A peer sent us an AROUND message """
        # cancel timer since we got our response
        self.timer.cancel()

        peer = event.createRemotePeer()
        # current number of neighbours
        nbNeighbours = len(self.neighbours)
        # last neighbour found
        last = self.neighbours[nbNeighbours-1]

        nodePos = self.node.getPosition() # our position
        bestPos = self.best.getPosition() # position of best node

        peerPos = Geometry.relativePosition(peer.getPosition(),
                                                 self.node.getPosition())

        # check if turn ends : we have at least 3 neighbours and either we got back
        # to the first peer (=> turn completed) or our last neighbour was in the
        # left half plane and this peer is in the right half plane
        if ( nbNeighbours > 2 ) and (peer.getId() == self.best.getId()) or (
            not Geometry.inHalfPlane(bestPos, nodePos, last.getPosition())
            and Geometry.inHalfPlane(bestPos, nodePos, peerPos) ):

            # Our awarenesse radius is the distance between us and our closest
            # neighbour, because we are sure to know all the entities between us
            # and the best.
            bestRelativePos = Geometry.relativePosition(bestPos, nodePos)
            minDistance = Geometry.distance(bestRelativePos, nodePos)
            self.node.setAwarenessRadius(minDistance)

            # register these peers with the peerManager and connect !
            manager = self.node.getPeersManager()
            for p in self.neighbours:
                # FIXME : should we add the peer upon receiving the CONNECT msg?
                manager.addPeer(p)
                factory = EventFactory.getInstance(PeerEvent.TYPE)
                hello = factory.createHELLO()
                hello.setRecipientAddress(p.getAddress())
                self.node.dispatch(hello)

            self.node.setState(Connecting())
        else:
            # add this peer to our list of neighbours
            self.addPeerAround(peer)

            # send this peer a queryaround message
            bestDist = Geometry.distance(bestPos, nodePos)
            factory = EventFactory.getInstance(PeerEvent.TYPE)
            queryaround = factory.createQUERYAROUND(self.best.getId(), bestDist)
            queryaround.setRecipientAddress(peer.getAddress())
            self.node.dispatch(queryaround)
            self.startTimer()
Beispiel #12
0
    def DETECT(self, event):
        """ Notification that a peer is moving towards us"""
        peer = event.createRemotePeer()
        id_ = peer.getId()
        manager = self.node.getPeersManager()
        # Sanity check 1: don't connect with ourselves
        if id_ == self.node.getId():
            return
        # Sanity check 2: don't connect with someone too far from us
        dist = Geometry.distance(self.node.getPosition(), peer.getPosition())
        ar = self.node.getAwarenessRadius()
        if dist > ar:
            return

        # we are only interested by entities that are not yet in our peer list
        if not manager.hasPeer(id_):
            # Check we don't have too many peers, or have worse peers than this one
            if manager.isPeerAccepted(peer):
                # Connect to this peer
                factory = EventFactory.getInstance(PeerEvent.TYPE)
                hello = factory.createHELLO()
                hello.setRecipientAddress(peer.getAddress())
                self.node.dispatch(hello)
Beispiel #13
0
 def setLocalPosition(self, nodePosition):
     """ Set the local position in the coordinate system with origin nodePosition
     nodePosition: position of the node, e.g. [12,56]
     """
     self.localPosition = Geometry.localPosition(self.getPosition(), nodePosition)
Beispiel #14
0
    def UPDATE(self, event):
        """ A peer sent us an UPDATE message."""
        # extract the peer from the event
        peer = event.createPeer()
        id_ = peer.getId()

        manager = self.node.getPeersManager()
        if not manager.hasPeer(id_):
            self.logger.debug('UPDATE from %s, but we are not connected' % peer.getId())
            return

        # save peer old value
        oldPeer = manager.getPeer(event.getArg(protocol.ARG_ID))

        # update peer
        manager.updatePeer(peer)

        # notify the controller that a peer has changed
        ctlFact = EventFactory.getInstance(ControlEvent.TYPE)
        upd = ctlFact.createUPDATE(peer)
        self.node.dispatch(upd)

        oldPosition = oldPeer.getPosition()
        newPosition = peer.getPosition()
        nodePosition = self.node.getPosition()

        oldAR = oldPeer.getAwarenessRadius()
        newAR = peer.getAwarenessRadius()

        peerFct = EventFactory.getInstance(PeerEvent.TYPE)

        # peer position changed
        if not oldPosition == newPosition:
            # verify entities that could be interested by the entity id
            for ent in manager.enumeratePeers():
                if ent.getId() == id_:
                    continue
                itsAR = ent.getAwarenessRadius()

                # get distance between self and ent
                ourDist = Geometry.distance(nodePosition, ent.getPosition())

                # get distance between ent and entity id
                theirDist = Geometry.distance(ent.getPosition(), newPosition)

                # get old distance between ent and entity id
                theirOldDist = Geometry.distance(ent.getPosition(), oldPosition)

                if (theirDist < itsAR < theirOldDist) or \
                       (theirDist < ourDist < theirOldDist):
                    # modified entity enters in Awareness Area of ent
                    # OR moving entity is now closer than us to ent

                    # The moving peer is notified to a fixed entity
                    detect = peerFct.createDETECT(peer)
                    detect.setRecipientAddress(ent.getAddress())
                    self.node.dispatch(detect)

                elif oldAR < theirOldDist and newAR >= theirDist:
                    # The entity is notified to the moving peer
                    detect = peerFct.createDETECT(ent)
                    detect.setRecipientAddress(peer.getAddress())
                    self.node.dispatch(detect)

        # peer awareness radius changed
        if not oldAR == newAR:
            self.logger.debug('AR updated %d -> %d' % (oldAR, newAR))
            # verify entities that could be interested by the modified entity.
            for ent in manager.enumeratePeers():
                if ent.getId() == id_:
                    continue
                # get distance between ent and modified entity
                position = ent.getPosition()
                theirDist = Geometry.distance(position, newPosition)
                theirOldDist = Geometry.distance(position, oldPosition)
                self.logger.debug('peer %s: position (%s), old dist %d, new dist %d' %
                    (ent.getId(), str(position), theirDist, theirOldDist))

                if oldAR < theirOldDist and newAR >= theirDist:
                    # ent enter in Awareness Area of modified entity.
                    # DETECT message sent to modified entity.
                    detect = peerFct.createDETECT(ent)
                    detect.setRecipientAddress(peer.getAddress())
                    self.node.dispatch(detect)