Implemented the inundation, strange type error encountered when testing
This commit is contained in:
		@@ -1,7 +1,7 @@
 | 
			
		||||
# Copyright (C) 2020 by eichhornchen, ÿnérant
 | 
			
		||||
# SPDX-License-Identifier: GPL-3.0-or-later
 | 
			
		||||
from datetime import datetime
 | 
			
		||||
from random import randint
 | 
			
		||||
from random import randint, uniform
 | 
			
		||||
from typing import Any, Tuple
 | 
			
		||||
#from ipaddress import IPv6Address
 | 
			
		||||
from threading import Thread, RLock
 | 
			
		||||
@@ -61,6 +61,7 @@ class Squirrel(Hazelnut):
 | 
			
		||||
 | 
			
		||||
        self.history = []
 | 
			
		||||
        self.received_messages = dict()
 | 
			
		||||
        self.recent_messages = dict() #of the form [Pkt(DataTLV), date of first reception, dict(neighbour, date of the next send, nb of times it has already been sent)]
 | 
			
		||||
        self.history_pad = curses.newpad(curses.LINES - 2, curses.COLS)
 | 
			
		||||
        self.input_pad = curses.newpad(1, curses.COLS)
 | 
			
		||||
        self.emoji_pad = curses.newpad(18, 12)
 | 
			
		||||
@@ -75,7 +76,7 @@ class Squirrel(Hazelnut):
 | 
			
		||||
        self.activehazelnuts = dict() #of the form [hazelnut, time of last
 | 
			
		||||
        #hello, time of last long hello, is symmetric]
 | 
			
		||||
        self.nbNS = 0
 | 
			
		||||
        self.minNS = 3 #minimal number of symetric neighbours a squirrel needs
 | 
			
		||||
        self.minNS = 3 #minimal number of symmetric neighbours a squirrel needs
 | 
			
		||||
        #to have.
 | 
			
		||||
        
 | 
			
		||||
        self.add_system_message(f"Listening on {self.address}:{self.port}")
 | 
			
		||||
@@ -294,18 +295,93 @@ class Squirrel(Hazelnut):
 | 
			
		||||
        if self.last_line == len(self.history) - 2:
 | 
			
		||||
            self.last_line += 1
 | 
			
		||||
 | 
			
		||||
    def receive_message_from(self, msg: str, sender_id: int, nonce: int) -> bool:
 | 
			
		||||
    def receive_message_from(self, tlv: DataTLV, msg: str, sender_id: int, nonce: int, relay: Hazelnut) -> bool:
 | 
			
		||||
        """
 | 
			
		||||
        This method is called by a DataTLV, sent by a real person.
 | 
			
		||||
        This add the message in the history if not already done.
 | 
			
		||||
        Returns True iff the message was not already received previously.
 | 
			
		||||
        """
 | 
			
		||||
        if (sender_id, nonce) not in self.recent_messages:
 | 
			
		||||
            #If it is a new message, add it to recent_messages
 | 
			
		||||
            d = self.make_inundation_dict()
 | 
			
		||||
            pkt = Packet().construct(tlv)
 | 
			
		||||
            self.recent_messages[(sender_id, nonce)] = [pkt, time.time(), d]
 | 
			
		||||
        
 | 
			
		||||
        #in all cases, remove the sender from the list of neighbours to be inundated
 | 
			
		||||
        self.remove_from_inundation(relay, sender_id, nonce)
 | 
			
		||||
        
 | 
			
		||||
        if (sender_id, nonce) in self.received_messages:
 | 
			
		||||
            return False
 | 
			
		||||
 | 
			
		||||
        self.add_message(msg)
 | 
			
		||||
        self.add_message(msg) #for display purposes
 | 
			
		||||
        self.received_messages[(sender_id, nonce)] = Message(msg, sender_id, nonce)
 | 
			
		||||
        return True
 | 
			
		||||
    
 | 
			
		||||
    def make_inundation_dict(self) -> dict:
 | 
			
		||||
        """
 | 
			
		||||
        Takes the activehazels dictionnary and returns a list of [hazel, date+random, 0]
 | 
			
		||||
        """
 | 
			
		||||
        res = dict()
 | 
			
		||||
        l = list(self.activehazelnuts.items())
 | 
			
		||||
        for key, hazel in l:
 | 
			
		||||
            if hazel[3]: #Only if the neighbour is symmetric
 | 
			
		||||
                next_send = uniform(1, 2)
 | 
			
		||||
                res[key] = [hazel[0], time.time()+next_send, 0]
 | 
			
		||||
        return res
 | 
			
		||||
    
 | 
			
		||||
    def remove_from_inundation(self, hazel: Hazelnut, sender_id: int, nonce: int) -> None:
 | 
			
		||||
        """
 | 
			
		||||
        Remove the sender from the list of neighbours to be inundated
 | 
			
		||||
        """
 | 
			
		||||
        if (sender_id, nonce) in self.recent_messages:
 | 
			
		||||
            #If a peer is late in its acknowledgement, the absence of the previous if causes an error.
 | 
			
		||||
            self.recent_messages[(sender_id, nonce)][2].pop((hazel.address, hazel.port), None)
 | 
			
		||||
        
 | 
			
		||||
            if not self.recent_messages[(sender_id, nonce)][2] : #If dictionnary is empty, remove the message
 | 
			
		||||
                    self.recent_messages.pop((sender_id, nonce), None)
 | 
			
		||||
    
 | 
			
		||||
    def clean_inundation(self):
 | 
			
		||||
        """
 | 
			
		||||
        Remove messages which are overdue (older than 2 minutes) from the inundation dictionnary.
 | 
			
		||||
        """
 | 
			
		||||
        self.refresh_lock.acquire()
 | 
			
		||||
        
 | 
			
		||||
        for key in self.recent_messages:
 | 
			
		||||
            if time.time()-self.recent_messages[key][1] > 120:
 | 
			
		||||
                self.recent_messages.pop(key)
 | 
			
		||||
        
 | 
			
		||||
        self.refresh_lock.release()
 | 
			
		||||
                
 | 
			
		||||
    def main_inundation(self):
 | 
			
		||||
        """
 | 
			
		||||
        The main inundation function.
 | 
			
		||||
        """
 | 
			
		||||
        self.refresh_lock.acquire()
 | 
			
		||||
            
 | 
			
		||||
        for key in self.recent_messages:
 | 
			
		||||
            for key2 in self.recent_messages[key][2]:
 | 
			
		||||
                if time.time()-self.recent_messages[key][2][key2][1] >= 0:
 | 
			
		||||
                    #send the packet if it is overdue
 | 
			
		||||
                    self.send_packet(self.recent_messages[key][2][key2][0], self.recent_messages[key][0])
 | 
			
		||||
                
 | 
			
		||||
                a = self.recent_messages[key][2][key2][2]
 | 
			
		||||
                
 | 
			
		||||
                if a==5: #the neighbour is not reactive enough
 | 
			
		||||
                    gatlv = GoAwayTLV().construct(GoAwayType.TIMEOUT, "No acknowledge")
 | 
			
		||||
                    pkt = Packet().construct(gatlv)
 | 
			
		||||
                    self.send_packet(
 | 
			
		||||
                    self.recent_messages[key][2][key2][0], pkt)
 | 
			
		||||
                    self.activehazelnuts.pop(key2)
 | 
			
		||||
                    self.potentialhazelnuts[key2] = self.recent_messages[key][2][key2][0]
 | 
			
		||||
                    self.recent_messages[key][2].pop(key2)
 | 
			
		||||
                
 | 
			
		||||
                #change the time until the next send
 | 
			
		||||
                self.recent_messages[key][2][key2][2] = a+1
 | 
			
		||||
                next_send = uniform(2**(a-1), 2**a)
 | 
			
		||||
                self.recent_messages[key][2][key2][1] = time.time()+next_send
 | 
			
		||||
                
 | 
			
		||||
        
 | 
			
		||||
        self.refresh_lock.release()
 | 
			
		||||
 | 
			
		||||
    def add_system_message(self, msg: str) -> None:
 | 
			
		||||
        """
 | 
			
		||||
@@ -649,6 +725,11 @@ class Inondator(Thread):
 | 
			
		||||
    
 | 
			
		||||
    def run(self) -> None:
 | 
			
		||||
        while True:
 | 
			
		||||
            #clean the dictionnary
 | 
			
		||||
            self.squirrel.clean_inundation()
 | 
			
		||||
            
 | 
			
		||||
            #inundate
 | 
			
		||||
            self.squirrel.main_inundation()
 | 
			
		||||
            
 | 
			
		||||
 | 
			
		||||
class Message:
 | 
			
		||||
 
 | 
			
		||||
@@ -165,8 +165,11 @@ class HelloTLV(TLV):
 | 
			
		||||
            timeHL = squirrel.activehazelnuts[(sender.address, sender.port)]
 | 
			
		||||
        if self.is_long and self.dest_id == squirrel.id :
 | 
			
		||||
            timeHL = time.time()
 | 
			
		||||
 | 
			
		||||
        #Make sure the sender is not in the potential hazelnuts
 | 
			
		||||
        squirrel.remove_from_potential(sender.address, sender.port)
 | 
			
		||||
        
 | 
			
		||||
 | 
			
		||||
        #Add entry to/actualize the active hazelnuts dictionnary
 | 
			
		||||
        squirrel.activehazelnuts[(sender.address, sender.port)] = [sender, timeH,\
 | 
			
		||||
                                                                   timeHL, True]
 | 
			
		||||
        squirrel.nbNS += 1
 | 
			
		||||
@@ -260,7 +263,7 @@ class DataTLV(TLV):
 | 
			
		||||
        # Acknowledge the packet
 | 
			
		||||
        squirrel.send_packet(sender, Packet.construct(AckTLV.construct(self.sender_id, self.nonce)))
 | 
			
		||||
        
 | 
			
		||||
        if not squirrel.receive_message_from(msg, self.sender_id, self.nonce):
 | 
			
		||||
        if not squirrel.receive_message_from(self, msg, self.sender_id, self.nonce, sender):
 | 
			
		||||
            # The message was already received, do not print it
 | 
			
		||||
            return
 | 
			
		||||
 | 
			
		||||
@@ -312,8 +315,11 @@ class AckTLV(TLV):
 | 
			
		||||
            socket.htonl(self.nonce).to_bytes(4, sys.byteorder)
 | 
			
		||||
 | 
			
		||||
    def handle(self, squirrel: Any, sender: Any) -> None:
 | 
			
		||||
        # TODO Implement AckTLV
 | 
			
		||||
        squirrel.add_system_message("I received an AckTLV. I don't know what to do with it. Please implement me!")
 | 
			
		||||
        """
 | 
			
		||||
        When an AckTLV is received, we know that we do not have to inundate that neighbour anymore.
 | 
			
		||||
        """
 | 
			
		||||
        squirrel.add_system_message("I received an AckTLV")
 | 
			
		||||
        squirrel.remove_from_inundation(sender, self.sender_id, self.nonce)
 | 
			
		||||
 | 
			
		||||
    @staticmethod
 | 
			
		||||
    def construct(sender_id: int, nonce: int) -> "AckTLV":
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user