def __init__(self, event_queue, init_data=None):
     super(NewPredecessorListener, self).__init__()
     self.event_queue = event_queue
     self.listening_port = config.getint('NewPredecessorListener', 'Port')
     self.predecessor_data = None
     self.predecessor_listening_thread = None
     self._stop_event = threading.Event()
     self.init_data = init_data
Exemplo n.º 2
0
 def handle_new_predecessor_request_event(self, event):
     # The moment we have a new predecessor this means that the client before our predecessor
     # has a new next next hop address (which is our address) and our predecessor has new next next hop (which is
     # our next hop)
     self.predecessor = event.data['client_address']
     self_address = (helpers.get_self_ip_address(),
                     config.getint('NewPredecessorListener', 'Port'))
     # Special case if we have only 2 nodes left
     if self.predecessor[0] == self.next_hop_info[0]:
         self.sending_queue.put(
             events.NewNextNextHop(self.predecessor, self_address))
         self.next_next_hop_info = (helpers.get_self_ip_address(),
                                    config.getint('NewPredecessorListener',
                                                  'Port'))
     else:
         # We send information to predecessor of our predecessor about his new next next hop address
         self.sending_queue.put(
             events.NewNextNextHop(self_address, self.predecessor))
         # We send information to our predecessor about his new next next hop
         self.sending_queue.put(
             events.NewNextNextHop(self.next_hop_info, self_address))
Exemplo n.º 3
0
def connect_to_existing_client(connection):
    # main queue holding network events
    main_queue = queue.Queue(maxsize=0)
    paint_queue = queue.Queue(maxsize=0)

    # Retrieving time from a ntp server thread
    time_offset = [0]
    helpers.initialize_offset(time_offset)
    time_synchronizer = TimeSynchronizer(time_offset)
    time_synchronizer.start()

    # Listening for a new client thread
    new_client_listener = NewClientListener(main_queue)
    new_client_listener.start()

    # Listening for a new predecessor thread
    new_predecessor_listener = NewPredecessorListener(main_queue)
    new_predecessor_listener.start()

    # We send the client request containing our data so anothe rclient could connect as a predecessor
    new_client_request = events.NewClientRequestEvent(
        (helpers.get_self_ip_address(),
         config.getint('NewPredecessorListener', 'Port')))
    message = helpers.event_to_message(new_client_request)
    message_size = (len(message)).to_bytes(8, byteorder='big')
    connection.send(message_size)
    connection.send(message)

    # After we send the request we are waiting for the response with init_data
    message_size = connection.recv(8)
    message_size = int.from_bytes(message_size, byteorder='big')
    data = b''
    while len(data) < message_size:
        packet = connection.recv(message_size - len(data))
        if not packet:
            return None
        data += packet

    init_data = (json.loads(data.decode('utf-8')))['data']
    model = ModelThread(main_queue, paint_queue, time_offset, init_data,
                        connection)
    model.start()

    # We start the painter as it must be in the main thread
    painter = Painter(paint_queue, main_queue)
    painter.start_drawing()
Exemplo n.º 4
0
 def __init__(self, paint_queue, master_queue):
     self.master = tkinter.Tk()
     self.critical_section_string = tk.StringVar()
     self.master.protocol("WM_DELETE_WINDOW", self.on_closing)
     self.paint_queue = paint_queue
     self.master_queue = master_queue
     self.drawing_area = tkinter.Canvas(self.master, bg='white', width=config.getint('Tkinter', 'CanvasX'), height=config.getint('Tkinter', 'CanvasY'))
     self.drawing_area.pack()
     self.drawing_button = tkinter.Button(self.master, text="Draw/Erase", command=self.change_drawing_color)
     self.drawing_button.pack(side=tkinter.LEFT, expand=tkinter.TRUE)
     self.drawing_button = tkinter.Button(self.master, text="Take board", command=self.want_to_enter_critial_section)
     self.drawing_button.pack(side=tkinter.RIGHT, expand=tkinter.TRUE)
     self.critical_section = tkinter.Label(self.master, textvariable=self.critical_section_string)
     self.critical_section.pack(side=tk.RIGHT, expand=tkinter.TRUE)
     self.drawing_area.bind("<Motion>", self.motion)
     self.drawing_area.bind("<ButtonPress-1>", self.left_but_down)
     self.drawing_area.bind("<ButtonRelease-1>", self.left_but_up)
     self.running = True
     self.drawing_color = 'black'
     self.critical_section_string.set('Board Open')
 def __init__(self, event_queue):
     super(NewClientListener, self).__init__()
     self.event_queue = event_queue
     self.listening_port = config.getint('NewClientListener', 'Port')
     self._stop_event = threading.Event()
Exemplo n.º 6
0
    helpers.initialize_offset(time_offset)
    time_synchronizer = TimeSynchronizer(time_offset)
    time_synchronizer.start()

    # Listening for a new client thread
    new_client_listener = NewClientListener(main_queue)
    new_client_listener.start()

    # Listening for a new predecessor thread
    new_predecessor_listener = NewPredecessorListener(main_queue)
    new_predecessor_listener.start()

    model = ModelThread(main_queue, paint_queue, time_offset)
    model.start()

    # We start the painter as it must be in the main thread
    painter = Painter(paint_queue, main_queue)
    painter.start_drawing()


if __name__ == "__main__":
    if len(sys.argv) > 1 and sys.argv[1] == '0':
        start_new_group()
    else:
        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        logger.info('Connecting to: {}'.format(
            config.getint('NewClientListener', 'Port')))
        ip = config.get('ConnectionInfo', 'Ip')
        port = config.getint('ConnectionInfo', 'Port')
        s.connect((ip, port))
        connect_to_existing_client(s)
Exemplo n.º 7
0
    def handle_new_client_request(self, event):
        # At first we want to receive information to properly connect as new predecessor after sending init_data
        message_size = event.data['connection'].recv(8)
        message_size = int.from_bytes(message_size, byteorder='big')
        message = b''
        while len(message) < message_size:
            packet = event.data['connection'].recv(message_size - len(message))
            if not packet:
                return None
            message += packet
        client_request = json.loads(message.decode('utf-8'))

        first_client = not self.next_hop_info
        # When we detect a new client connecting we want to;
        # 1.Send him the initial data over the connection we already established
        # 2.Connect to him as a predecessor

        # Gather the initial board state (only the coloured spots)
        marked_spots = [(x, y) for x in range(len(self.board_state))
                        for y in range(len(self.board_state[x]))
                        if self.board_state[x][y] == 1]
        # If we have next hop information we send it, if we do not have we are the first client so we send our
        # information as the first hop information
        next_hop = (helpers.get_self_ip_address(),
                    config.getint(
                        'NewPredecessorListener',
                        'Port')) if first_client else self.next_hop_info
        # If we are the first client next next hop is None
        response = events.NewClientResponseEvent(next_hop,
                                                 self.next_next_hop_info,
                                                 marked_spots,
                                                 self.critical_section)
        message = helpers.event_to_message(response)
        message_size = (len(message)).to_bytes(8, byteorder='big')
        event.data['connection'].send(message_size)
        event.data['connection'].send(message)

        try:
            message = event.data['connection'].recv(8)
        except Exception as ex:
            if message == b'':
                # Only case when we have a succesfull read of 0 bytes is when other socket shutdowns normally
                pass
            else:
                logger.error(ex)
                #Client did not initializ correctly so we abort the process
                return
        # If we are not the first client we have to update our next next hop to our previous next hop
        if not first_client:
            self.next_next_hop_info = self.next_hop_info
        else:
            # If we are the first client we update our next next hop info to self address
            self.next_next_hop_info = (helpers.get_self_ip_address(),
                                       config.getint('NewPredecessorListener',
                                                     'Port'))

        # We stop current message sender if it exists
        if self.message_sender:
            self.message_sender.stop()

        # We update our next hop info with the newest client request
        self.next_hop_info = client_request['data']['address']
        ip, port = self.next_hop_info
        # We establish a new connection and a new message sender
        connection = socket.create_connection((ip, port), 100)
        self.sending_queue = queue.Queue(maxsize=0)
        self.message_sender = MessageSender(self.event_queue,
                                            self.sending_queue, connection)
        self.message_sender.start()
        if first_client and self.last_token != None:
            # If we are the first client we start passing of the token
            self.sending_queue.put(events.TokenPassEvent(self.last_token))
Exemplo n.º 8
0
    def __init__(self,
                 event_queue,
                 paint_queue,
                 time_offset,
                 init_data=None,
                 init_connection=None):
        super(ModelThread, self).__init__()

        # Queues
        self.event_queue = event_queue
        self.paint_queue = paint_queue

        #Event handling
        self.handlers = {}
        self.initialize_handlers()

        # Unique uuid identifying clients in the network
        self.uuid = uuid.uuid4().hex
        # Flag indicating weather we want to enter critical section when the token comes
        self.want_to_enter_critical_section = False
        # Information about critical section like the timestamp and client uuid which is in the section
        self.critical_section = None
        # Time offset between ntp server and local time
        self.time_offset = time_offset
        # Value of the last token we have received
        self.last_token = None

        # Initial board state
        self.board_state = [[
            0 for _ in range(config.getint('Tkinter', 'CanvasY'))
        ] for _ in range(config.getint('Tkinter', 'CanvasX'))]

        # If we are the first client
        if not init_data:
            self.next_hop_info = None
            self.next_next_hop_info = None
            self.sending_queue = None
            self.message_sender = None
            self.predecessor = None
            self.last_token = 0
        else:
            self.next_hop_info = init_data['next_hop']
            if not init_data['next_next_hop']:
                # If there is no next_next_hop init data in the response we are the second client so we set
                # next next hop as our address
                self.next_next_hop_info = (helpers.get_self_ip_address(),
                                           config.getint(
                                               'NewPredecessorListener',
                                               'Port'))
            else:
                # If there are more thant two clients we set the value from the response
                self.next_next_hop_info = init_data['next_next_hop']

            # Address of our predecessor
            self.predecessor = init_connection.getsockname()

            # We initialize connection to our next hop and we start sending queue
            ip, port = init_data['next_hop']
            s = socket.create_connection((ip, port))
            self.sending_queue = queue.Queue(maxsize=0)
            self.message_sender = MessageSender(self.event_queue,
                                                self.sending_queue, s)
            self.message_sender.start()
            self.initialize_board(init_data['board_state'])
            if init_data['critical_section_state']:
                self.critical_section = init_data['critical_section_state']
                self.paint_queue.put({'type': DrawingQueueEvent.BOARD_CLOSED})

            # We signal that client has initialized properly
            init_connection.shutdown(1)
            init_connection.close()

        # We start a dummy message sender event which will create dummy messages to detect connection breaks
        self.dummy_message_sender = DummyMessageSender(self.event_queue,
                                                       self.uuid)
        self.dummy_message_sender.start()