Esempio n. 1
0
File: node.py Progetto: hanlhe/OLSR
class Node:
    __executor__ = ThreadPoolExecutor(max_workers=10)
    __clock__ = Clock()
    __msg_queue__ = None
    __terminate__ = False

    def __init__(self, node_id, dst=None, msg=None, timestamp=None):
        self.nid = node_id
        self.dst = dst
        self.msg = msg
        self.timestamp = timestamp
        self.fromfilename = 'from' + self.nid + '.txt'
        self.tofilename = 'to' + self.nid + '.txt'
        self.receivefilename = self.nid + 'received.txt'
        self.__message_processor__ = {
            'HELLO': self.__receive_hello__,
            'TC': self.__receive_tc__,
            'DATA': self.__receive_data__
        }
        self.__msg_cache__ = dict()
        self.__route__ = Route(node_id)

    def __msg_cache_reset__(self):
        """ Reset cache for new message forwading period. """
        self.__msg_cache__ = dict()

    @property
    def time(self):
        return self.__clock__.time

    def tick(self):
        self.__clock__.tick()

    __hello__ = '* {} HELLO UNIDIR {} BIDIR {} MPR {}\n'

    def __send_hello__(self):
        sender = self.nid
        unidir = ' '.join(map(str, self.__route__.unidir))
        bidir = ' '.join(map(str, self.__route__.bidir))
        mpr = ' '.join(map(str, self.__route__.mpr))
        hello = self.__hello__.format(sender, unidir, bidir, mpr)
        # print(hello)
        with open(self.fromfilename, 'a') as from_me:
            from_me.write(hello)

    __tc__ = '* {} TC {} {} MS {}\n'

    def __send_tc__(self):
        sender = self.nid
        source = self.nid
        seqno = self.__route__.ms_seqno
        ms = ' '.join(map(str, self.__route__.ms))
        tc = self.__tc__.format(sender, source, seqno, ms)
        with open(self.fromfilename, 'a') as from_me:
            from_me.write(tc)

    __data__ = '{} {} DATA {} {} {}\n'

    def __send_data__(self):
        next_hop = self.__route__.get_route(self.dst)

        # If next_hop is not None, send message to that node.
        if next_hop:
            sender = self.nid
            originator = self.nid
            dst = self.dst
            msg = self.msg
            data = self.__data__.format(next_hop, sender, originator, dst, msg)
            with open(self.fromfilename, 'a') as from_me:
                from_me.write(data)
        # Otherwise, delay the message for 30 seconds.
        else:
            self.timestamp += 30

    def __check_timeout__(self):
        self.__route__.check_timeout()

    def __follow_to_file__(self):
        try:
            open(self.tofilename, 'r').close()
        except IOError:
            open(self.tofilename, 'w').close()
        with open(self.tofilename, 'r') as to_me:
            to_me.seek(0, 2)
            while not self.__terminate__:
                line = to_me.readline()
                if not line:
                    sleep(0.1)
                    continue
                yield line

    def __receive_hello__(self, msg):
        with open(self.receivefilename, 'a') as received:
            received.write(msg)
        msg = msg[:-1]
        neighbor = msg[2]
        unidir, rest = msg.split('UNIDIR ')[1].split(' BIDIR ')
        bidir, mpr = rest.split(' MPR ')
        to_set = lambda x: set() if x == '' else set(x.split(' '))
        self.__route__.hello_update(neighbor, to_set(unidir), to_set(bidir),
                                    to_set(mpr))

    def __receive_tc__(self, msg):
        with open(self.receivefilename, 'a') as received:
            received.write(msg)
        msg = msg[:-1]
        neighbor = msg[2]
        s, ms = msg.split(' TC ')[1].split(' MS ')
        source, seqno = s.split(' ')

        # If the TC message was originated by the node itself, discard it.
        if source == self.nid:
            return

        # If the TC message in cache is newer or the same (cache[source] >=
        # seqno), discard it.
        try:
            if self.__msg_cache__[source] >= seqno:
                return
        except KeyError:
            pass
        finally:
            self.__msg_cache__[source] = seqno

        to_set = lambda x: set() if x == '' else set(x.split(' '))
        self.__route__.tc_update(source, to_set(ms), int(seqno))

        # Forward message if node itself is sender's mpr and TTL is greater
        # than 1.
        if self.__route__.mpr_of(neighbor):
            tc = self.__tc__.format(self.nid, source, seqno, ms)
            with open(self.fromfilename, 'a') as from_me:
                from_me.write(tc)

    def __receive_data__(self, msg):
        with open(self.receivefilename, 'a') as received:
            received.write(msg)
        msg_list = msg[:-1].split(' ')

        # If current node is the destination of the message, no further
        # operation is needed.
        if self.nid == msg_list[4]:
            return

        # Otherwise, get next hop to the destination, forward the message.
        next_hop = self.__route__.get_route(msg_list[4])

        # If next_hop is not None, forward the message to that node. Change
        # next_hop and fromnbr before sending.
        if next_hop:
            new_msg = ' '.join([next_hop, self.nid] + msg_list[2:]) + '\n'
            with open(self.fromfilename, 'a') as from_me:
                from_me.write(new_msg)
        # Otherwise, just drop the message.
        else:
            pass

    def __msg_processor__(self):
        for msg in self.__msg_queue__:
            self.__message_processor__[msg.split(' ')[2]](msg)
            if self.__terminate__:
                break

    def start(self):
        self.__msg_queue__ = \
            (self.__executor__.submit(self.__follow_to_file__)).result()
        self.__executor__.submit(self.__msg_processor__)
        while self.time <= 122:
            self.__executor__.submit(self.__check_timeout__)

            # Send message at specific timestamp.
            if self.time == self.timestamp:
                self.__executor__.submit(self.__send_data__)

            # Each node sends a hello message every 5 seconds.
            if self.time % 5 == 0:
                self.__executor__.submit(self.__send_hello__)

            # Reset message cache before each TC flood time cycle.
            if self.time % 10 == 8:
                self.__executor__.submit(self.__msg_cache_reset__)

            # Every node with a non-empty MS sets creates and floods a TC
            # message every 10 seconds.
            if self.time % 10 == 0 and self.__route__.ms:
                self.__executor__.submit(self.__send_tc__)

            sleep(1)
            self.tick()
        self.__terminate__ = True
        sleep(1)