def send_message_non_acknowledged(self, message, address=None):
     if self.transport:
         for i in range(
                 0, global_network_config.get_config_value("BURST_NUMBER")):
             # logger.info(" ---------- sending message {0} to address {1}".format(str(message), str(address)))
             self.transport.write(message.serialize(), address)
             time.sleep(
                 global_network_config.get_config_value(
                     "TIME_BETWEEN_BURSTS"))
         return True
     else:
         logger.error("self.transport is not set up yet")
         return False
    def send_message_acknowledged(self, message, address=None, blocking=False):
        assert isinstance(message, Protocol)
        self._messages_to_be_acknowledged[message.checksum] = (message,
                                                               address)
        self._messages_to_be_acknowledged_timeout[message.checksum] = 0
        if blocking:
            self._message_events[message.checksum] = threading.Event()
            # logger.info(" -------------- creating threading event for message {0}".format(str(message)))
            # make sure that the threading event is created before the message is sent out
            # else there will be race condition
            logger.info(
                "Created threading.Event for message with checksum {0}".format(
                    str(message.checksum)))
            successfully_sent = self.send_message_non_acknowledged(
                message, address)
            if not successfully_sent:
                logger.error("Failed sending message!")
                return False
            return_value = self._message_events[message.checksum].wait(
                global_network_config.get_config_value(
                    "MAX_TIME_WAITING_FOR_ACKNOWLEDGEMENTS") * 3)
            del self._message_events[message.checksum]

            if not self.transport:
                # self.transport is set to None if the connection was not established yet via
                # self.transport.connect(...) and it is written the first time to the udp channel
                self.clean_up_for_message(message)
                return False

            if return_value:
                # successfully sent the register message and got an acknowledge
                return True
            else:
                # timeout case
                self.clean_up_for_message(message)
                logger.warn("timeout occurred for waiting for acknowledgement")
                return False

        else:
            self.send_message_non_acknowledged(message, address)
            return True
    def __init__(self):
        self._new_message_cv = threading.Condition()

        self.datagram_received_function = self.print_message
        # primitive data types are thread safe in python, thus they are not secured by a lock
        self._messages_to_be_acknowledged = {}
        self._messages_to_be_acknowledged_timeout = {}
        self._acknowledge_messages_address_couples = []
        self._registered_endpoints = {}
        self._registered_endpoints_for_acknowledgements = []
        self.number_of_dropped_messages = 0
        self._message_history = collections.deque(
            maxlen=global_network_config.get_config_value("HISTORY_LENGTH"))
        # this is only to speed up memory access times
        self._message_history_dictionary = {}
        self._message_events = {}

        self._not_acknowledged_messages_counter = 0

        self.__shutdown = False
        self.check_acknowledgements_thread = threading.Thread(
            target=self.check_acknowledgements)
    def check_acknowledgements(self):

        while True:
            next_message = None
            # logger.debug("Check_acknowledgements thread looping")

            # return if shutdown requested
            if self.__shutdown:
                logger.info("Shutdown requested!")
                return

            # get new message thread safe
            self._new_message_cv.acquire()
            while True:
                self._new_message_cv.wait(
                    CHECK_ACKNOWLEDGEMENTS_THREAD_MAX_WAIT_TIME)
                if len(self._acknowledge_messages_address_couples) > 0 or len(
                        self._messages_to_be_acknowledged
                ) > 0:  # changed or into and
                    break
            # print "active"
            if len(self._acknowledge_messages_address_couples) > 0:
                next_message, address = self._acknowledge_messages_address_couples.pop(
                )
                assert isinstance(next_message, Protocol)
            self._new_message_cv.release()

            # delete received messages from _messages_to_be_acknowledged
            if next_message is not None:
                if next_message.message_content in self._messages_to_be_acknowledged.iterkeys(
                ):
                    logger.debug(
                        "Message {0} was acknowledged successfully".format(
                            str(next_message)))
                    del self._messages_to_be_acknowledged[
                        next_message.message_content]
                    del self._messages_to_be_acknowledged_timeout[
                        next_message.message_content]
                else:
                    logger.warn(
                        "Message {0} was acknowledged that was sent by another endpoint "
                        "or was already acknowledged!".format(
                            str(next_message)))

            # check messages for timeout
            # logger.debug("check_acknowledgements checking for messages timeout")
            timed_out_messages = []
            for key, (
                    message,
                    address) in self._messages_to_be_acknowledged.iteritems():
                self._messages_to_be_acknowledged_timeout[
                    key] += CHECK_ACKNOWLEDGEMENTS_THREAD_MAX_WAIT_TIME
                if self._messages_to_be_acknowledged_timeout[key] > \
                        global_network_config.get_config_value("MAX_TIME_WAITING_FOR_ACKNOWLEDGEMENTS"):
                    timed_out_messages.append(key)

            # message timeout handling
            for key in timed_out_messages:
                # this is not the right strategy:
                # logger.warn("Message {0} dropped because of timeout".format(self._messages_to_be_acknowledged[key]))
                # del self._messages_to_be_acknowledged[key]
                # del self._messages_to_be_acknowledged_timeout[key]
                # self.number_of_dropped_messages += 1
                t_message = self._messages_to_be_acknowledged[key][0]
                logger.warn(
                    "Message {0} is going to be resent as no acknowledge was received yet"
                    .format(t_message))
                successfully_sent = self.send_message_non_acknowledged(
                    t_message, self._messages_to_be_acknowledged[key][1])
                if not successfully_sent:
                    self.clean_up_for_message(t_message)
                    logger.warn(
                        "Stop resending messages as the connection is not up!")
                    self._message_events[t_message.checksum].set()
Beispiel #5
0
 def create_unique_checksum_and_salt(self):
     if self.salt is None:
         self.salt = uuid.uuid4().hex[:global_network_config.get_config_value("SALT_LENGTH")]
     self.checksum = self.generate_checksum()
     return self.checksum + ":" + self.salt
Beispiel #6
0
 def generate_checksum(self):
     return hashlib.md5(str(self.sequence_number) + self.salt +
                        self.message_content).hexdigest()[:global_network_config.get_config_value("HASH_LENGTH")]
 def startProtocol(self):
     CommunicationEndpoint.startProtocol(self)
     self.transport.connect(global_network_config.get_config_value("SERVER_IP"),
                            global_network_config.get_config_value("SERVER_UDP_PORT"))
     logger.info("self.transport {0}".format(str(self.transport)))
     logger.info("Protocol started")