Example #1
0
    def update_data(self):
        """

        Returns:

        """
        count = 1
        lim = 2
        while True:
            try:
                data = protocol.recv_data(self.sock)
            except socket.timeout:
                break

            data = protocol.parse(data)
            if data['type'] == protocol.Type.CONTROL and \
                    data['subtype'] == protocol.Subtype.CONTROL.stream_end:
                if count < lim:
                    count += 1
                else:
                    break

            elif data['type'] == protocol.Type.SNAKE and \
                    data['subtype'] == protocol.Subtype.SNAKE.new:
                snake = game.objects.Snake.create_snake(
                    game.objects.Point(*data['head']), data['name'],
                    data['mass'], data['tail'])
                self.snakes[data['id']] = snake
                if self.key == data['id']:
                    self.render_control.player = snake

            elif data['type'] == protocol.Type.SNAKE and \
                    data['subtype'] == protocol.Subtype.SNAKE.full_update:
                if not data['id'] in self.snakes:
                    continue
                self.snakes[data['id']].update_snake(data['mass'],
                                                     data['head'],
                                                     data['tail'])

            elif data['type'] == protocol.Type.SNAKE and \
                    data['subtype'] == protocol.Subtype.SNAKE.delete:
                del self.snakes[data['id']]

            elif data['type'] == protocol.Type.ORB and \
                    data['subtype'] == protocol.Subtype.ORB.new:
                orb = game.objects.Orb(
                    game.objects.Point(data['x'], data['y']), data['mass'],
                    data['color'])
                self.orbs[data['id']] = orb

            elif data['type'] == protocol.Type.ORB and \
                    data['subtype'] == protocol.Subtype.ORB.delete:
                del self.orbs[data['id']]
Example #2
0
  def _recv(self):
    # Get the header first.
    try:
      header = ''
      while len(header) < protocol.HEADER_SIZE:
        received = self.socket.recv(protocol.HEADER_SIZE - len(header))
        header += received
        if len(received) == 0:
          return None
    except:
      return None

    size = protocol.packet_length(header)
    msg = ""
    while len(msg) < size:
      received = self.socket.recv(size)
      msg += received
      if len(received) == 0:
        LOGGER.warning("Server socket died while receiving.")
        return None
    return protocol.parse(header, msg)
Example #3
0
  def _recv(self):
    # Get the header first.
    try:
      header = ''
      while len(header) < protocol.HEADER_SIZE:
        received = self.socket.recv(protocol.HEADER_SIZE - len(header))
        header += received
        if len(received) == 0:
          return None
    except:
      return None

    size = protocol.packet_length(header)
    msg = ""
    while len(msg) < size:
      received = self.socket.recv(size)
      msg += received
      if len(received) == 0:
        LOGGER.warning("Server socket died while receiving.")
        return None
    return protocol.parse(header, msg)
Example #4
0
    def __init__(self, ip, name):
        """

        Args:
            ip (str): valid ip of the server.
            name (str): the name of the player.
        """
        # variables declaration
        self.sock = socket.socket()
        self.key = None

        self.snakes = {}
        self.orbs = {}

        self.display = pygame.display.get_surface().get_rect()
        self.board = None
        self.render_control = None

        # initial connection
        self.sock.connect((ip, protocol.PORT))
        self.sock.settimeout(None)

        # get server initial
        while True:
            data = protocol.parse(protocol.recv_data(self.sock))
            if data['type'] == protocol.Type.INITIAL and \
                    data['subtype'] == protocol.Subtype.INITIAL.server:
                self.board = pygame.Rect(0, 0, data['width'], data['height'])
                self.key = data['id']
                break
        self.render_control = game.render.Render(self.display, self.board,
                                                 self.snakes, self.orbs)

        # send client initial
        protocol.send_data(self.sock, protocol.initial_client(name))

        # end init function and add timeout
        self.sock.settimeout(0.001)
Example #5
0
 def handler(incoming):
     cmd = parse(incoming)
     return execute(cmd)
Example #6
0
    def run(self):
        """Execute the receiver thread."""
        while self.running:
            # repeatedly try to connect to server
            while not self.connected:
                self.logger.info('waiting for connection')
                try:
                    self.socket.connect((self.server_ip, self.port))
                except:
                    time.sleep(2)
                else:
                    self.connected = True
                    message = protocol.thread.new_socket(socket=self.socket)
                    self.network_queue.put(message)
            self.logger.info('connected to server')

            # loop running while the client is connected
            while self.connected:

                # if receive fail, go back to reconnection
                try:
                    size_str = self.socket.recv(4)
                except:
                    self.connected = False

                if size_str != '':
                    size = protocol.get_size(size_str)
                    received = ''

                    # receive until the whole message is received
                    while size != 0:

                        try:
                            part = self.socket.recv(size)
                        except:
                            part = ''

                        # if the connection is close,
                        # return to waiting to connection
                        if part == '':
                            self.connected = False
                            break

                        received += part
                        size -= len(part)

                    # if the messaged was received without failing,
                    # pass it to the logic
                    if self.connected:
                        self.logger.debug(
                            'received message. length: %s' % len(received))
                        message = protocol.parse(received)

                        self.logic_queue.put(message)

                        # if the message type is 'kill', the thread will exit
                        # this must happen here and not in the logic thread,
                        # because the logic thread has no way to send a message
                        # to this thread because it doesn't have a queue.
                        if message['type'] == 'kill':
                            self.socket.close()
                            self.connected = False
                            self.running = False
                            break
                else:
                    self.connected = False

            self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
Example #7
0
 def parse_cmd(self, cmd, size, args, transp):
     protocol.parse(cmd, size, args)
Example #8
0
 def parse_cmd(self, cmd, size, args, transport):
     protocol.parse(cmd, size, args, transport)
Example #9
0
    def run(self):
        """
        Execute the restore thread.

        The thread first collect all blocks from the clients.
        Then, It maps the received blocks to a giant dict.

        Example:
            {1:
                {blocks: {1: ['10.0.0.9/file.dat_1.data',
                             '10.0.0.10/file.dat_1.data',
                             '10.0.0.11/file.dat_1.data'],
                          2: ['10.0.0.9/file.dat_2.data',
                             '10.0.0.10/file.dat_2.data',
                             '10.0.0.11/file.dat_2.data'],
                          3: ['10.0.0.9/file.dat_3.data',
                             '10.0.0.10/file.dat_3.data',
                             '10.0.0.11/file.dat_3.data']},
                'path': '10.0.0.10/file.dat_1.metadata'},

        2:
                {blocks: {4: ['10.0.0.9/file.dat_4.data',
                             '10.0.0.10/file.dat_4.data',
                             '10.0.0.11/file.dat_4.data'],
                          5: ['10.0.0.9/file.dat_5.data',
                             '10.0.0.10/file.dat_5.data',
                             '10.0.0.11/file.dat_5.data'],
                          6: ['10.0.0.9/file.dat_6.data',
                             '10.0.0.10/file.dat_6.data',
                             '10.0.0.11/file.dat_6.data']},
                'path': '10.0.0.9/file.dat_2.metadata'}
            }

            After every block is mapped, the thread exemine if
            the file can be restored. If the file can be restored,
            the thread create missing parts and write the data to
            the path in 'self.real_file'.

        Raises:
            Exception: Description
        """
        self.logger.info(self.name + ' thread started')

        # receiving all blocks until the clients finished sending.
        start_time = time.time()
        while not all(self.clients.values()) and time.time() < start_time + 30:
            try:
                message = self.restore_queue.get(timeout=3)
            except:
                self.logger.debug('waiting for blocks...')
            else:
                # if received a massage, reset timeout
                start_time = time.time()

                message_type = message['type']
                self.logger.debug(
                    'received message of type \'%s\'' % message_type)

                if message_type == 'block':
                    self.received_block(message)
                elif message_type == 'file_sent':
                    self.clients[message['client']] = True
                elif message_type == 'exit':
                    self.exit_thread(success=False)
                    return
                else:
                    log = 'unknown message type: %s. message not processed'
                    self.logger.warning(log % message_type)

        self.logger.info('finished collecting blocks of file %s' %
                         self.virtual_file)

        # mapping the restored file blocks
        mapping = {}
        for path in self.get_blocks_names(block_type=protocol.METADATA_BLOCK):
            basename = os.path.basename(path)
            file_info = parse_file_name(basename)

            number = file_info['number']
            if number.isdigit():
                number = int(number)
                mapping[number] = {'path': path, 'blocks': {}}

        # insert records for missing metadata blocks into the mapping
        for metadata_number in xrange(1, self.validation_number + 1):
            if metadata_number not in mapping:
                mapping[metadata_number] = {'path': None, 'blocks': {}}

            start_number = 1 + self.validation_level * (metadata_number - 1)
            end_number = self.validation_level * metadata_number

            # insert paths of data blocks matching he missing metadata block
            for data_number in xrange(start_number, end_number + 1):
                blocks = mapping[metadata_number]['blocks']
                if data_number <= self.block_number:
                    blocks[data_number] = self.get_blocks_names(
                        block_type=protocol.DATA_BLOCK, number=data_number)

        self.logger.debug('file blocks mapping:\n' + pprint.pformat(mapping))

        # mapping missing / corrupted blocks
        valid_blocks = {}
        missing_data = {}
        missing_metadata = []
        validation_warning = True

        for metadata_number in mapping:
            metadata_path = mapping[metadata_number]['path']
            blocks_dict = mapping[metadata_number]['blocks']

            missing_data[metadata_number] = []

            # check if the metadata can be used
            valid_metadata = True
            if metadata_path is not None:
                try:
                    f = open(metadata_path, 'rb')
                    metadata = protocol.parse(f.read())
                    f.close()

                    if type(metadata) != dict:
                        raise Exception()

                except:
                    valid_metadata = False
            else:
                valid_metadata = False

            if valid_metadata:
                # if the metadata can be used, validate the blocks against it
                for block_number in blocks_dict:

                    if 'hashes' in metadata:
                        hashes = metadata['hashes']
                        if block_number in hashes:
                            block_hash = hashes[block_number]

                    block_list = blocks_dict[block_number]

                    if block_list == []:
                        missing_data[metadata_number].append(block_number)

                    for path in block_list:
                        f = open(path, 'rb')
                        content = f.read()
                        f.close()

                        validated_hash = encrypt.hash_string(content)
                        if validated_hash.lower() == block_hash.lower():
                            valid_blocks[block_number] = path
                            break

                '''
                if all variant of the blocks were tested against the metadata
                and none of them are valid, then add the block to the missing
                data. Later, try to recreate them
                '''
                for block_number in blocks_dict:
                    if block_number not in valid_blocks:
                        if block_number not in missing_data[metadata_number]:
                            missing_data[metadata_number].append(block_number)
            else:
                # if the metadata is not usable, choose the most common block
                missing_metadata.append(metadata_number)

                for block_number in blocks_dict:
                    if blocks_dict[block_number] != []:
                        content = []
                        for path in blocks_dict[block_number]:
                            f = open(path, 'rb')
                            content.append((path, f.read()))
                            f.close()

                        path, _ = max(set(content), key=content.count)
                        basename = os.path.basename(path)
                        number = parse_file_name(basename)['number']
                        number = int(number)
                        valid_blocks[number] = path
                    else:
                        missing_data[metadata_number].append(block_number)

                if validation_warning:
                    self.logger.warning('some blocks are not validated')
                    validation_warning = False

        self.logger.debug('valid blocks: %s' % pprint.pformat(valid_blocks))
        self.logger.debug('missing data: %s' % pprint.pformat(missing_data))
        self.logger.debug('missing metadata: %s' %
                          pprint.pformat(missing_metadata))

        # check if file can be restored, and recreate missing parts
        corrupted = False
        for metadata_number in missing_data:
            missing_count = len(missing_data[metadata_number])
            # if more then one block is missing per metadata block,
            # the file cannot be restored
            if missing_count > 1:
                corrupted = True
                break
            elif missing_count == 1:
                # if only one block is missing per metadata block, rebuild it
                if metadata_number not in missing_metadata:
                    # read metadata block
                    with open(mapping[metadata_number]['path'], 'rb') as f:
                        metadata = protocol.parse(f.read())

                    # calculate the first and last number of data block
                    # of the current metadata block
                    start_number = 1 + (self.validation_level *
                                        (metadata_number - 1))
                    end_number = self.validation_level * metadata_number
                    if end_number > self.block_number:
                        end_number = self.block_number

                    # restore the missing block using the metadata
                    restored = metadata['xor']
                    missing_block_number = missing_data[metadata_number][0]

                    for block_number in xrange(start_number, end_number + 1):
                        if block_number != missing_block_number:
                            with open(valid_blocks[block_number], 'rb') as f:
                                content = f.read()
                            restored = encrypt.xor_strings(restored, content)

                    # if the hash of the block is valid, write it to file
                    restored_hash = encrypt.hash_string(restored)
                    metadata_hash = metadata['hashes'][missing_block_number]

                    if restored_hash.lower() == metadata_hash.lower():
                        file_name = build_file_name(
                            block_type=protocol.DATA_BLOCK,
                            name=self.virtual_file,
                            number=missing_block_number)
                        path = os.path.join(self.temp, file_name)
                        restored_block = open(path, 'wb')
                        restored_block.write(restored)
                        restored_block.close()

                        valid_blocks[missing_block_number] = path
                    else:
                        corrupted = True
                        break
                else:
                    corrupted = True
                    break

        # if file can be restored, restore it
        if not corrupted:
            real_file = open(self.real_file, 'wb')
            for block_number in xrange(1, self.block_number + 1):
                path = valid_blocks[block_number]
                f = open(path, 'rb')
                real_file.write(f.read())
                f.close()
            real_file.close()
            self.logger.info('\'%s\' restored successfully' %
                             self.virtual_file)

        # else, tell the logic thread
        else:
            err = '\'%s\' is corrupted, could not restore' % self.virtual_file
            self.logger.error(err)
            message = protocol.thread.error(thread_id=self.ident, message=err)
            self.logic_queue.put(message)

        # executing exit operations
        self.callback()
        self.exit_thread(success=not corrupted)
 def testParseCmd(self):
     testString = "er"
     results = protocol.parse(testString)
     self.assertEqual(results, ("er", []))
 def testParseCmdManyArg(self):
     testString = "er\trt\twere"
     results = protocol.parse(testString)
     self.assertEqual(results, ("er", ["rt", "were"]))
 def testParseCmdArg(self):
     testString = "er\trt"
     results = protocol.parse(testString)
     self.assertEqual(results, ("er", ["rt"]))