Пример #1
0
    def handle_ack(self, packet):
        # TODO: sequence number overflow
        if self.piggyback and packet.Data != FIELD_NOT_SET and len(
                packet.Data) > 0:
            self.handle_data(packet)
        self.acknowledgement = packet.Acknowledgement
        # print("ack: ", packet.Acknowledgement)
        i = 0
        while i < len(self.timers):
            timer = self.timers[i]
            if timer._callbackArgs[0].SequenceNumber < packet.Acknowledgement:
                timer.cancel()
                self.timers = self.timers[:i] + self.timers[i + 1:]
                i -= 1
            i += 1

        if self.rip_timer != None:
            self.rip_timer.cancel()
            self.rip_timer.extend(Seconds(2))
            self.rip_timer.start()
            return

        self.send_window_start = max(self.send_window_start,
                                     packet.Acknowledgement)
        self.send_window_data()

        if self.state == PEEP_Base.TEARDOWN and self.sent_all():
            self.send_rip()
            self.rip_timer = Timer(Seconds(2), self.abort_connection)
            self.rip_timer.start()
Пример #2
0
 def initiate_teardown(self):
     # print('teardown start')
     self.state = PEEP_Base.TEARDOWN
     if self.sent_all():
         self.send_rip()
         self.rip_timer = Timer(Seconds(2), self.abort_connection)
         self.rip_timer.start()
Пример #3
0
    def status(self, writer, poll=None):
        if not self.__started:
            self.transport.write("Can't get status. Not yet started\n")
            return
        if poll != None:
            # We're changing the polling time. Cancel the current, then
            # set the new polling time
            try:
                poll = int(poll)
            except:
                self.transport.write(
                    "Polling time must be an integer. Got %s" % poll)
                return
            if poll < 0:
                self.transport.write(
                    "Polling time must be a positive integer. Got %d" % poll)
                return
            if self.__pollingCallback:
                self.__pollingCallback.cancel()
                if poll == 0:
                    self.__pollingCallback = None
            self.__poll = poll
        template = """
        Max Paths: %(Max_Path_Count)s
        Completed Paths: %(Completed_Path_Count)s
        Currently Executing Paths: %(Current_Path_Count)s
    %(Current_Execution_Details)s
        Address Data:
    %(Addr_Stats)s"""
        if self.ptsp.finished():
            template = ("FINISHED: %s\n" %
                        str(self.ptsp.finalResult())) + template
        templateData = {}
        templateData["Max_Path_Count"] = self.ptsp.maxPaths()
        templateData["Completed_Path_Count"] = self.ptsp.completedPathCount()

        currStr = ''
        currentExecutions = self.ptsp.currentExecutions()
        currentPathCount = 0
        for execId, paths, addr, finished in currentExecutions:
            currStr += "\t\t%s:\t%s\t%s\n" % (addr, execId, paths)
            start, end = paths
            currentPathCount += (end - start) + 1
        templateData["Current_Path_Count"] = currentPathCount
        addrStr = "\t\t%-15s\t%-10s\t%-10s\t%-10s\t%s\n" % (
            "Address", "Jobs Sent", "Completed Jobs", "Errors", "Paid")
        for addrData in self.ptsp.iterAddrStats():
            addrStr += "\t\t%-15s\t%-10s\t%-10s\t%s\t%s\n" % (
                addrData.addr, addrData.jobsSent, addrData.jobsCompleted,
                addrData.jobErrors, addrData.paid)

        templateData["Current_Execution_Details"] = currStr
        templateData["Addr_Stats"] = addrStr

        self.transport.write((template % templateData) + "\n")
        if self.__poll:
            # if we have a polling time set, fire.
            self.__pollingCallback = Timer(lambda: self.status(writer))
            self.__pollingCallback.run(self.__poll)
Пример #4
0
 def send_packet(self, packet):
     # print(self, "send packet: ", packet)
     self.transport.write(packet.__serialize__())
     if packet.Type != PEEPPacket.SYN and packet.Type != PEEPPacket.DATA and packet.Type != PEEPPacket.RIP:
         return
     timer = Timer(Seconds(1), self.send_packet, packet)
     self.timers.append(timer)
     timer.start()
Пример #5
0
 def __init__(self, fragId, totalSize, parentContainer):
     self._fragId = fragId
     self._totalSize = totalSize
     self._parentContainer = parentContainer
     self._received = 0
     self._bufferStream = io.BytesIO()
     self._offsetsReceived = set([])
     self._cleanUpTimer = Timer(Minutes(5), self._removeFromParentContainer)
     self._cleanUpTimer.start()
Пример #6
0
    class FragStorage:
        def __init__(self, fragId, totalSize, parentContainer):
            self._fragId = fragId
            self._totalSize = totalSize
            self._parentContainer = parentContainer
            self._received = 0
            self._bufferStream = io.BytesIO()
            self._offsetsReceived = set([])
            self._cleanUpTimer = Timer(Minutes(5),
                                       self._removeFromParentContainer)
            self._cleanUpTimer.start()

        def _removeFromParentContainer(self):
            if self._fragId in self._parentContainer:
                del self._parentContainer[self._fragId]

        def insert(self, fragOffset, fragData):
            if fragOffset in self._offsetsReceived: return
            self._offsetsReceived.add(fragOffset)
            self._bufferStream.seek(fragOffset)
            self._bufferStream.write(fragData)
            self._received += len(fragData)
            self._cleanUpTimer.extend(Minutes(5))

        def isComplete(self):
            return self._received == self._totalSize

        def getData(self):
            return self._bufferStream.getvalue()

        def cleanup(self):
            self._cleanUpTimer.expire()
            return self.getData()
Пример #7
0
class PEEP_Base(StackingProtocol):

    INIT, HANDSHAKE, TRANS, TEARDOWN = [0, 1, 2, 3]

    def __init__(self):
        super().__init__()
        self.state = PEEP_Base.INIT
        self.window_size = 10
        self.chunk_size = 1024
        self.transport = None
        self.deserializer = None
        self.base_sequence_number = None
        self.sequence_number = None
        self.expected_sequence_number = None
        self.send_window_start = None
        self.send_window_end = None
        self.receive_window_start = None
        self.receive_window_end = None
        self.data_size = 0
        self.data = bytes()
        self.timers = []
        self.received_data = []
        self.rip_timer = None
        self.rip_sequence_number = None
        self.piggyback = False

    def data_received(self, data):
        # print("data received")
        self.deserializer.update(data)
        for packet in self.deserializer.nextPackets():
            if isinstance(packet, PEEPPacket) and packet.verifyChecksum():
                self.handle_packets(packet)

    def handle_packets(self, packet):
        typenum = packet.Type
        if typenum == PEEPPacket.SYN and self.state == PEEP_Base.INIT:
            # print('received SYN')
            self.handle_syn(packet)
        elif typenum == PEEPPacket.SYNACK and self.state == PEEP_Base.HANDSHAKE:
            print('-------------PEEP received SYNACK-------------')
            self.handle_synack(packet)
        elif typenum == PEEPPacket.ACK:
            # print("received ACK")
            self.handle_ack(packet)
        elif typenum == PEEPPacket.DATA and (self.state == PEEP_Base.TRANS or
                                             self.state == PEEP_Base.TEARDOWN):
            # print('received Data')
            self.handle_data(packet)
        elif typenum == PEEPPacket.RIP and (self.state == PEEP_Base.TRANS or
                                            self.state == PEEP_Base.TEARDOWN):
            # print('received RIP')
            self.handle_rip(packet)
        elif typenum == PEEPPacket.RIPACK and self.state == PEEP_Base.TEARDOWN:
            # print('received RIPACK')
            self.handle_ripack(packet)
        else:
            print('received packet in bad state. type: ', typenum, " state ",
                  self.state)

    def handle_syn(self, packet):
        # print('checksum of SYN is correct')
        packetback = PEEPPacket()
        if packet.Data != FIELD_NOT_SET and packet.Data.decode(
        ) == "piggyback":
            # print("syn: enable piggybacking")
            packetback.Data = "piggyback".encode()
            self.piggyback = True
        packetback.Acknowledgement = packet.SequenceNumber + 1
        self.sequence_number = random.randint(0, 2**16)
        self.base_sequence_number = self.sequence_number + 1
        self.expected_sequence_number = packet.SequenceNumber + 1
        self.send_window_start = self.base_sequence_number
        self.send_window_end = self.base_sequence_number
        packetback.SequenceNumber = self.sequence_number
        packetback.Type = PEEPPacket.SYNACK
        packetback.updateChecksum()
        self.send_packet(packetback)
        self.state = PEEP_Base.HANDSHAKE
        # maybe set this state to trans in case the ack in handshake gets dropped
        # print('sent SYNACK')

    def handle_synack(self, packet):
        # print("Received synack", packet)
        if packet.Acknowledgement != self.sequence_number:
            return
        i = 0
        while i < len(self.timers):
            timer = self.timers[i]
            if timer._callbackArgs[0].SequenceNumber < packet.Acknowledgement:
                timer.cancel()
                self.timers = self.timers[:i] + self.timers[i + 1:]
                i -= 1
            i += 1
        if packet.Data != FIELD_NOT_SET and packet.Data.decode(
        ) == "piggyback":
            # print("synack: enable piggybacking")
            self.piggyback = True
        packet_to_send = PEEPPacket()
        packet_to_send.Type = PEEPPacket.ACK
        packet_to_send.SequenceNumber = self.sequence_number
        #        packet_to_send.SequenceNumber = packet.Acknowledgement
        packet_to_send.Acknowledgement = packet.SequenceNumber + 1
        packet_to_send.updateChecksum()
        self.base_sequence_number = packet.Acknowledgement
        self.expected_sequence_number = packet.SequenceNumber + 1
        self.send_window_start = self.base_sequence_number
        self.send_window_end = self.base_sequence_number
        self.sequence_number = self.base_sequence_number
        # print("Sending Back Ack")
        self.send_packet(packet_to_send)
        self.state = PEEP_Base.TRANS  # transmission state
        # Open upper layer transport
        # print("connection_made to higher protocol")
        self.higherProtocol().connection_made(
            PEEP_Transport(self.transport, self))

    def handle_ack(self, packet):
        # TODO: sequence number overflow
        if self.piggyback and packet.Data != FIELD_NOT_SET and len(
                packet.Data) > 0:
            self.handle_data(packet)
        self.acknowledgement = packet.Acknowledgement
        # print("ack: ", packet.Acknowledgement)
        i = 0
        while i < len(self.timers):
            timer = self.timers[i]
            if timer._callbackArgs[0].SequenceNumber < packet.Acknowledgement:
                timer.cancel()
                self.timers = self.timers[:i] + self.timers[i + 1:]
                i -= 1
            i += 1

        if self.rip_timer != None:
            self.rip_timer.cancel()
            self.rip_timer.extend(Seconds(2))
            self.rip_timer.start()
            return

        self.send_window_start = max(self.send_window_start,
                                     packet.Acknowledgement)
        self.send_window_data()

        if self.state == PEEP_Base.TEARDOWN and self.sent_all():
            self.send_rip()
            self.rip_timer = Timer(Seconds(2), self.abort_connection)
            self.rip_timer.start()

    def handle_data(self, packet):
        self.received_data.append(packet)
        if packet.SequenceNumber == self.expected_sequence_number:
            self.pass_data_up()

        ack_packet = PEEPPacket()
        if self.piggyback:
            try_getting_piggyback_data = self.get_piggyback_data()
            if try_getting_piggyback_data != None:
                ack_packet.Data = try_getting_piggyback_data
                ack_packet.SequenceNumber = self.get_piggyback_sequence_number(
                )

        ack_packet.Acknowledgement = self.expected_sequence_number
        ack_packet.Type = PEEPPacket.ACK
        ack_packet.updateChecksum()
        # print("sending ack")
        # print("ack: ", self.expected_sequence_number)
        self.send_packet(ack_packet)

        if self.state == PEEP_Base.TEARDOWN and self.received_all():
            self.send_rip_ack(self.rip_sequence_number + 1)

    def get_piggyback_data(self):
        if self.sequence_number - self.base_sequence_number >= self.data_size:
            i = self.sequence_number - self.base_sequence_number
            ret = self.data[i:min(
                i + self.chunk_size, self.send_window_start +
                self.window_size * self.chunk_size)]
            self.sequence_number += len(ret)
            self.send_window_end += len(ret)
            return ret

    def get_piggyback_sequence_number(self):
        return self.sequence_number

    def pass_data_up(self):
        self.received_data.sort(key=lambda packet: packet.SequenceNumber)
        i = 0
        while i < len(self.received_data):
            packet = self.received_data[i]
            if packet.SequenceNumber == self.expected_sequence_number:
                self.higherProtocol().data_received(packet.Data)
                self.expected_sequence_number += len(packet.Data)
                self.received_data = self.received_data[:
                                                        i] + self.received_data[
                                                            i + 1:]
                i -= 1
            i += 1

    def transmit_data(self, data):
        self.data += data
        self.data_size += len(data)
        # print("transmitting data size: ", self.data_size)
        self.send_window_data()

    def send_window_data(self):
        # print('send window data')
        while self.send_window_end - self.send_window_start < self.window_size * self.chunk_size:
            if self.sequence_number - self.base_sequence_number >= self.data_size:
                # print("all bytes have been sent from me")
                return
            self.send_next_chunk()
        # print("end send window data")

    def send_next_chunk(self):
        # print('send next chunk')
        packet = PEEPPacket()
        i = self.sequence_number - self.base_sequence_number
        packet.Type = PEEPPacket.DATA
        packet.SequenceNumber = self.sequence_number
        packet.Data = self.data[
            i:min(i + self.chunk_size, self.send_window_start +
                  self.window_size * self.chunk_size)]
        packet.updateChecksum()
        # print("sending: " , packet.SequenceNumber)
        self.send_packet(packet)
        self.sequence_number += len(packet.Data)
        self.send_window_end += len(packet.Data)

    def connection_made(self, transport):
        raise NotImplementedError

    def connection_lost(self, exc):
        self.transport.close()
        self.transport = None
        asyncio.get_event_loop().stop()

    def send_packet(self, packet):
        # print(self, "send packet: ", packet)
        self.transport.write(packet.__serialize__())
        if packet.Type != PEEPPacket.SYN and packet.Type != PEEPPacket.DATA and packet.Type != PEEPPacket.RIP:
            return
        timer = Timer(Seconds(1), self.send_packet, packet)
        self.timers.append(timer)
        timer.start()

    def initiate_teardown(self):
        # print('teardown start')
        self.state = PEEP_Base.TEARDOWN
        if self.sent_all():
            self.send_rip()
            self.rip_timer = Timer(Seconds(2), self.abort_connection)
            self.rip_timer.start()

    def received_all(self):
        return self.rip_sequence_number == self.expected_sequence_number

    def sent_all(self):
        return self.sequence_number - self.base_sequence_number >= self.data_size

    def handle_rip(self, packet):
        self.state = PEEP_Base.TEARDOWN
        self.rip_sequence_number = packet.SequenceNumber
        if self.received_all():
            self.send_rip_ack(self.rip_sequence_number + 1)

    def send_rip(self):
        # print("send rip :", self)
        rip = PEEPPacket(Type=PEEPPacket.RIP)
        rip.SequenceNumber = self.sequence_number
        self.sequence_number += 1
        rip.updateChecksum()
        self.send_packet(rip)

    def send_rip_ack(self, ack):
        ripack = PEEPPacket(Type=PEEPPacket.RIPACK)
        ripack.Acknowledgement = ack
        ripack.updateChecksum()
        self.send_packet(ripack)

    def handle_ripack(self, packet):
        self.transport.close()

    def abort_connection(self):
        self.transport.close()
Пример #8
0
class ParallelTSPCLI(CLIShell):
        BANNER = """
    Parallel Traveling Salesman. Sends out paths to be computed
    by remote hosts. Results are collected until the best path
    is known. Execute 'start' to begin the computation. 
    Execute 'status' to see how things are going.
    """
        def __init__(self, ptsp):
            CLIShell.__init__(self, banner = self.BANNER)   

            self.ptsp = ptsp
            self.options = {}
            self.__poll = None
            self.__pollingCallback = None
            self.__started = False
            startHandler = CLIShell.CommandHandler("start",helpTxt="Start the parallelTsp",
                                                   defaultCb=self.start,
                                                   mode=CLIShell.CommandHandler.STANDARD_MODE)
            self.registerCommand(startHandler)
            #configHandler = CLIShell.CommandHandler("config",helpTxt="Show current config (can't change yet)",
            #                                        defaultCb=self.config,
            #                                        mode=CLIShell.CommandHandler.STANDARD_MODE)
            #self.registerCommand(configHandler)
            statusHandler = CLIShell.CommandHandler("status",helpTxt="Show current status",
                                                    defaultCb=self.status,
                                                    mode=CLIShell.CommandHandler.STANDARD_MODE)
            statusHandler.configure(1, self.status, helpTxt="Show status and set to poll the status",
                                    usage="[polling time]")
            self.registerCommand(statusHandler)
            #checkbalanceHandler = CLIShell.CommandHandler("balance", helpTxt="Check the current account balance",
            #                                              defaultCb=self.checkBalance,
            #                                              mode=CLIShell.CommandHandler.STANDARD_MODE)
            #self.registerCommand(checkbalanceHandler)
            sampleCodeString = CLIShell.CommandHandler("sample", helpTxt="Generate A sample remote code string",
                                                       mode=CLIShell.CommandHandler.STANDARD_MODE)
            sampleCodeString.configure(3, self.getSampleCodeString, 
                                       helpTxt="Get a sample code string for the given parameters", 
                                       usage="[startpath] [endpath] [filename]")
            self.registerCommand(sampleCodeString)
            
            #blacklistCommand = CLIShell.CommandHandler("blacklist", helpTxt="Get the list of blacklisted nodes",
            #                                           mode=CLIShell.CommandHandler.STANDARD_MODE,
            #                                           defaultCb=self.blacklistedAddrs)
            #self.registerCommand(blacklistCommand)
            
        def __checkBalanceResponse(self, f, writer):
            e = f.exception()
            if not e:
                self.transport.write("Current balance in account: %d\n" % f.result())
            else:
                self.transport.write("Check balance failed: {}\n".format(e))
            
        def checkBalance(self, writer):
            f = self.ptsp.wallet.checkBalance()
            f.add_done_callback(lambda f: self.__checkBalanceResponse(f, writer))
            
        def config(self, writer):
            for k, v in self.options.items():
                self.transport.write("%s: %s\n" % (k,v))
                
        def getSampleCodeString(self, writer, startPath, endPath, filename):
            try:
                startPath = int(startPath)
            except:
                writer("Invalid start path\n")
                return
            try:
                endPath = int(endPath)
            except:
                writer("Invalid end path\n")
                return
            codeStr = self.ptsp.getCodeString(startPath, endPath)
            with open(filename, "w+") as f:
                f.write(codeStr)
            writer("Wrote file %s\n" % filename)
            
        def blacklistedAddrs(self, writer):
            if not self.__started:
                self.transport.write("Can't get blacklist Not yet started\n")
                return
            bl = self.ptsp.auth.getBlacklist()
            writer("Blacklisted Addresses:\n")
            for addr in bl:
                writer("  %s\n" % addr)
            writer("\n")
                
        def status(self, writer, poll=None):
            if not self.__started:
                self.transport.write("Can't get status. Not yet started\n")
                return
            if poll != None:
                # We're changing the polling time. Cancel the current, then
                # set the new polling time
                try:
                    poll = int(poll)
                except:
                    self.transport.write("Polling time must be an integer. Got %s" % poll)
                    return
                if poll < 0:
                    self.transport.write("Polling time must be a positive integer. Got %d" % poll)
                    return
                if self.__pollingCallback:
                    self.__pollingCallback.cancel()
                    if poll == 0:
                        self.__pollingCallback = None
                self.__poll = poll
            template = """
        Max Paths: %(Max_Path_Count)s
        Completed Paths: %(Completed_Path_Count)s
        Currently Executing Paths: %(Current_Path_Count)s
    %(Current_Execution_Details)s
        Address Data:
    %(Addr_Stats)s"""
            if self.ptsp.finished():
                template = ("FINISHED: %s\n" % str(self.ptsp.finalResult())) + template
            templateData = {}
            templateData["Max_Path_Count"] = self.ptsp.maxPaths()
            templateData["Completed_Path_Count"] = self.ptsp.completedPathCount()
            
            currStr = ''
            currentExecutions = self.ptsp.currentExecutions()
            currentPathCount = 0
            for execId, paths, addr, finished in currentExecutions:
                currStr += "\t\t%s:\t%s\t%s\n" % (addr, execId, paths)
                start, end = paths
                currentPathCount += (end-start)+1
            templateData["Current_Path_Count"] = currentPathCount
            addrStr =  "\t\t%-15s\t%-10s\t%-10s\t%-10s\t%s\n" % ("Address", "Jobs Sent", "Completed Jobs", "Errors", "Paid")
            for addrData in self.ptsp.iterAddrStats():
                addrStr += "\t\t%-15s\t%-10s\t%-10s\t%s\t%s\n" % (addrData.addr, addrData.jobsSent, 
                                                                  addrData.jobsCompleted, addrData.jobErrors, 
                                                                  addrData.totalPaid())
                for payto in addrData.paid:
                    addrStr += "\t\t%-15s\t%-10s\t%-10s\t%-10s\t%s\n" % (" ", " ", " ", " ", "{}: {}".format(payto, addrData.paid[payto]))  
            
            templateData["Current_Execution_Details"] = currStr
            templateData["Addr_Stats"] = addrStr
            
            self.transport.write((template % templateData)+"\n")
            if self.__poll:
                # if we have a polling time set, fire.
                self.__pollingCallback = Timer(lambda: self.status(writer))
                self.__pollingCallback.run(self.__poll)
            
        def start(self, writer):
            if self.__started:
                self.transport("Program already started.\n")
                return
            self.__started=True
            coro = self.ptsp.start()
            future = asyncio.get_event_loop().create_task(coro)
            future.add_done_callback(lambda future: self.finish())
            #kargs = {}
            #parameters = self.options.getSection("ptsp.parameters")
            #if parameters.has_key("n"):
            #    kargs["n"] = int(parameters["n"])
            #if parameters.has_key("paths_per_parallel_execution"):
            #    kargs["pathsPerParallel"] = int(parameters["paths_per_parallel_execution"])
            #self.ptsp = ParallelTSP()#**kargs)
            
            
            #Parallel(self.ptsp, self.finish)
            
        def finish(self):
            #resultsFile = "tsp_results."+str(time.time())+".txt"
            self.transport.write("Finished computation\n")
            self.transport.write("\tResult: %s\n" % str(self.ptsp.finalResult()))
            if self.__pollingCallback:
                self.__pollingCallback.cancel()
                self.__pollingCallback = None
Пример #9
0
class PEEP(StackingProtocol):
    INIT, HANDSHAKE, TRANS, TEARDOWN = [0, 1, 2, 3]

    def __init__(self):
        super().__init__()
        self.state = PEEP.INIT
        self.window_size = 100
        self.chunk_size = 1024
        self.transport = None
        self.deserializer = None
        self.base_sequence_number = None
        self.sequence_number = None
        self.expected_sequence_number = None
        self.send_window_start = None
        self.send_window_end = None
        self.receive_window_start = None
        self.receive_window_end = None
        self.data_size = 0
        self.data = bytes()
        self.timers = []
        self.received_data = []
        self.rip_timer = None
        self.rip_sequence_number = None
        self.piggyback = False
        self.acknowledgement = None

    def data_received(self, data):
        print("data received")
        self.deserializer.update(data)
        for packet in self.deserializer.nextPackets():
            if isinstance(packet, PEEPPacket) and packet.verifyChecksum():
                self.handle_packets(packet)

    def handle_packets(self, packet):
        packet_type = packet.Type
        if packet_type == PEEPPacket.SYN and self.state == PEEP.INIT:
            print('received SYN')
            self.handle_syn(packet)
        elif packet_type == PEEPPacket.SYNACK and self.state == PEEP.HANDSHAKE:
            print('received SYNACK')
            self.handle_synack(packet)
        elif packet_type == PEEPPacket.ACK:
            print("received ACK")
            self.handle_ack(packet)
        elif packet_type == PEEPPacket.DATA and (self.state == PEEP.TRANS or
                                                 self.state == PEEP.TEARDOWN):
            print('received Data')
            self.handle_data(packet)
        elif packet_type == PEEPPacket.RIP and (self.state == PEEP.TRANS or
                                                self.state == PEEP.TEARDOWN):
            print('received RIP')
            self.handle_rip(packet)
        elif packet_type == PEEPPacket.RIPACK and self.state == PEEP.TEARDOWN:
            print('received RIP-ACK')
            self.handle_ripack()
        else:
            print('BAD PACKET. summary: ', packet.__repr__())

    def handle_syn(self, packet):
        print('checksum of SYN is correct')
        packetback = PEEPPacket()
        if packet.Data != FIELD_NOT_SET and packet.Data.decode(
        ) == "piggyback":
            print("syn: enable piggybacking")
            packetback.Data = "piggyback".encode()
            self.piggyback = True
        packetback.Acknowledgement = packet.SequenceNumber + 1
        self.sequence_number = random.randint(0, 2**16)
        self.base_sequence_number = self.sequence_number + 1
        self.expected_sequence_number = packet.SequenceNumber + 1
        self.send_window_start = self.base_sequence_number
        self.send_window_end = self.base_sequence_number
        packetback.SequenceNumber = self.sequence_number
        packetback.Type = PEEPPacket.SYNACK
        packetback.updateChecksum()
        self.send_packet(packetback)
        self.state = PEEP.HANDSHAKE
        print('sent SYNACK')

    def handle_synack(self, packet):
        print("Received synack")
        if packet.Data != FIELD_NOT_SET and packet.Data.decode(
        ) == "piggyback":
            print("synack: enable piggybacking")
            self.piggyback = True
        packet_to_send = PEEPPacket()
        packet_to_send.Type = PEEPPacket.ACK
        packet_to_send.SequenceNumber = packet.Acknowledgement
        packet_to_send.Acknowledgement = packet.SequenceNumber + 1
        packet_to_send.updateChecksum()
        self.base_sequence_number = packet.Acknowledgement
        self.expected_sequence_number = packet.SequenceNumber + 1
        self.send_window_start = self.base_sequence_number
        self.send_window_end = self.base_sequence_number
        self.sequence_number = self.base_sequence_number
        print("Sending Back Ack")
        self.send_packet(packet_to_send)
        self.state = PEEP.TRANS  # transmission state
        # Open upper layer transport
        print("connection_made to higher protocol")
        self.higherProtocol().connection_made(
            PeepTransport(self.transport, self))

    def handle_ack(self, packet):
        if self.piggyback and packet.Data != FIELD_NOT_SET and len(
                packet.Data) > 0:
            self.handle_data(packet)
        self.acknowledgement = packet.Acknowledgement
        print("ack: ", packet.Acknowledgement)
        i = 0
        while i < len(self.timers):
            timer = self.timers[i]
            if timer._callbackArgs[0].SequenceNumber < packet.Acknowledgement:
                timer.cancel()
                self.timers = self.timers[:i] + self.timers[i + 1:]
                i -= 1
            i += 1

        if self.rip_timer is not None:
            self.rip_timer.cancel()
            self.rip_timer.extend(Seconds(2))
            self.rip_timer.start()
            return

        self.send_window_start = max(self.send_window_start,
                                     packet.Acknowledgement)
        self.send_window_data()

        if self.state == PEEP.TEARDOWN and self.sent_all():
            self.send_rip()
            self.rip_timer = Timer(Seconds(2), self.abort_connection)
            self.rip_timer.start()

    def handle_data(self, packet):
        self.received_data.append(packet)
        if packet.SequenceNumber == self.expected_sequence_number:
            self.pass_data_up()

        ack_packet = PEEPPacket()
        if self.piggyback:
            try_getting_piggyback_data = self.get_piggyback_data()
            if try_getting_piggyback_data is not None:
                ack_packet.Data = try_getting_piggyback_data
                ack_packet.SequenceNumber = self.get_piggyback_sequence_number(
                )

        ack_packet.Acknowledgement = self.expected_sequence_number
        ack_packet.Type = PEEPPacket.ACK
        ack_packet.updateChecksum()
        print("Sending ACK")
        self.send_packet(ack_packet)

        if self.state == PEEP.TEARDOWN and self.received_all():
            self.send_rip_ack(self.rip_sequence_number + 1)

    def initiate_teardown(self):
        print('Start TEARDOWN')
        self.state = PEEP.TEARDOWN
        if self.sent_all():
            self.send_rip()
            self.rip_timer = Timer(Seconds(2), self.abort_connection)
            self.rip_timer.start()

    def received_all(self):
        return self.rip_sequence_number == self.expected_sequence_number

    def sent_all(self):
        return self.sequence_number - self.base_sequence_number >= self.data_size

    def get_piggyback_data(self):
        if self.sequence_number - self.base_sequence_number >= self.data_size:
            i = self.sequence_number - self.base_sequence_number
            ret = self.data[i:min(
                i + self.chunk_size, self.send_window_start +
                self.window_size * self.chunk_size)]
            self.sequence_number += len(ret)
            self.send_window_end += len(ret)
            return ret

    def get_piggyback_sequence_number(self):
        return self.sequence_number

    def transmit_data(self, data):
        self.data += data
        self.data_size += len(data)
        print("transmitting data size: ", self.data_size)
        self.send_window_data()

    def send_window_data(self):
        print('Sending Window Data')
        while self.send_window_end - self.send_window_start < self.window_size * self.chunk_size:
            if self.sequence_number - self.base_sequence_number >= self.data_size:
                print("Everything sent")
                return
            self.send_next_chunk()

    def pass_data_up(self):
        self.received_data.sort(
            key=lambda current_packet: current_packet.SequenceNumber)
        i = 0
        while i < len(self.received_data):
            packet = self.received_data[i]
            if packet.SequenceNumber == self.expected_sequence_number:
                self.higherProtocol().data_received(packet.Data)
                self.expected_sequence_number += len(packet.Data)
                self.received_data = self.received_data[:
                                                        i] + self.received_data[
                                                            i + 1:]
                i -= 1
            i += 1

    def send_next_chunk(self):
        print('send next chunk')
        next_packet = PEEPPacket()
        i = self.sequence_number - self.base_sequence_number
        next_packet.Type = PEEPPacket.DATA
        next_packet.SequenceNumber = self.sequence_number
        next_packet.Data = self.data[
            i:min(i + self.chunk_size, self.send_window_start +
                  self.window_size * self.chunk_size)]
        next_packet.updateChecksum()
        print("Now sending packet with seq number:",
              next_packet.SequenceNumber)
        self.send_packet(next_packet)
        self.sequence_number += len(next_packet.Data)
        self.send_window_end += len(next_packet.Data)

    def connection_made(self, transport):
        raise NotImplementedError

    def connection_lost(self, exc):
        self.transport.close()
        self.transport = None
        asyncio.get_event_loop().stop()

    def send_packet(self, packet):
        print(self, "send packet: ", packet)
        self.transport.write(packet.__serialize__())
        if packet.Type != PEEPPacket.SYN and packet.Type != PEEPPacket.DATA and packet.Type != PEEPPacket.RIP:
            return
        timer = Timer(Seconds(1), self.send_packet, packet)
        self.timers.append(timer)
        timer.start()

    """
        RIP's and TEARDOWN 
    """

    def handle_rip(self, packet):
        self.state = PEEP.TEARDOWN
        self.rip_sequence_number = packet.SequenceNumber
        if self.received_all():
            self.send_rip_ack(self.rip_sequence_number + 1)

    def send_rip(self):
        print("Sending RIP")
        rip_packet = PEEPPacket(Type=PEEPPacket.RIP)
        rip_packet.SequenceNumber = self.sequence_number
        self.sequence_number += 1
        rip_packet.updateChecksum()
        self.send_packet(rip_packet)

    def send_rip_ack(self, ack):
        print("Sending RIP ACK")
        rip_ack_packet = PEEPPacket(Type=PEEPPacket.RIPACK)
        rip_ack_packet.Acknowledgement = ack
        rip_ack_packet.updateChecksum()
        self.send_packet(rip_ack_packet)

    def handle_ripack(self):
        self.transport.close()

    def abort_connection(self):
        self.transport.close()
    def resend(self, resntPacket):
        if "DATA" in resntPacket.Type.upper():  #start timer again
            #get timer
            for seq, packet, timer, acked in self.sentBoxData:
                if seq == resntPacket.SeqNo:
                    timer.cancel()
                    index = self.sentBoxData.index((seq, packet, timer, acked))
                    pacTimer = Timer(Seconds(self.timeoutValue), self.timeout,
                                     packet)
                    pacTimer.start()
                    self.sentBoxData[index] = (
                        seq, packet, pacTimer, False
                    )  #packet seq, packet, timer, acked or not
                    #start timer
        elif "FIN" in resntPacket.Type.upper():
            currentTimer = self.sentBoxData[-1][2]
            currentTimer.cancel()
            currentTimer = Timer(Seconds(self.timeoutValue), self.timeout,
                                 self.sentBoxData[-1][1])
            currentTimer.start()
            self.sentBoxData[-1] = (self.sentBoxData[-1][0],
                                    self.sentBoxData[-1][1], currentTimer,
                                    False)  #last packet since its FIN
        elif "ACK" in resntPacket.Type.upper():
            if "SYN" in resntPacket.Type.upper():
                self.timHand.cancel()
            self.timHand = Timer(Seconds(self.timeoutValue), self.timeout,
                                 self.sentHand)
            self.timHand.start()

        elif "SYN" in resntPacket.Type.upper():
            self.stateCon = 0
            print("Im here")
            self.timHand.cancel()
            self.timHand = Timer(Seconds(self.timeoutValue), self.timeout,
                                 self.sentHand)
            self.timHand.start()

        resendPacket = RIPPacket(Type=resntPacket.Type,
                                 SeqNo=resntPacket.SeqNo,
                                 AckNo=resntPacket.AckNo,
                                 CRC=resntPacket.CRC,
                                 Data=resntPacket.Data)
        print("resend packet: Type = {}, SeqNo = {}, AckNo = {},\n CRC = {}".
              format(resntPacket.Type, resntPacket.SeqNo, resntPacket.AckNo,
                     resntPacket.CRC.decode()))
        self.transport.write(resendPacket.__serialize__())
    def send(self, pacType, PacData):
        sentPacket = RIPPacket()
        print("the packet type is: {}".format(pacType))
        #calculateSeqAck
        if "SYN" in pacType.upper() and "ACK" in pacType.upper():
            print("SYN ACK")
            #add Ack number
            sentPacket.AckNo = self.recHand.SeqNo + 1
            #add Seq
            sentPacket.SeqNo = self.SequenceNo  #random seq

        elif "ACK" in pacType.upper():
            if self.stateCon == 1:
                print("1 ACK")
                #add Ack number
                sentPacket.AckNo = self.recHand.SeqNo + 1
                #add Seq
                sentPacket.SeqNo = self.sentHand.SeqNo + 1

        elif "SYN" in pacType.upper():
            print("SYN")
            #add Ack number
            sentPacket.AckNo = 0
            #add Seq
            sentPacket.SeqNo = self.SequenceNo  #random seq

        elif "DATA" in pacType.upper() or "FIN" in pacType.upper():
            if self.sentHand is not None:
                print("1st Packet after the Handshake")
                #add Ack number
                sentPacket.AckNo = 0
                #add Seq
                sentPacket.SeqNo = self.recHand.AckNo
                #empty hands
                self.recHand = None
                self.sentHand = None
            else:
                #add Ack number
                sentPacket.AckNo = 0
                #add Seq
                sentPacket.SeqNo = self.sentBoxData[-1][0] + len(
                    self.sentBoxData[-1][1].Data
                )  #sequence number and data length of previouse sent packet

            if "FIN" in pacType.upper():
                self.stateCon = 3  #FIN state
        else:
            print("IM NOTHING{}".format(sentPacket.AckNo))

        #add Type
        sentPacket.Type = pacType

        #add Data
        sentPacket.Data = PacData

        #add checksum
        sentPacket.CRC = self.hashPacket(sentPacket)
        print("checksum is: {}".format(sentPacket.CRC.decode()))
        print("send Type ={}, Seq= {}, ACK= {}".format(sentPacket.Type,
                                                       sentPacket.SeqNo,
                                                       sentPacket.AckNo))
        #add packet to the sent list

        if "DATA" in pacType.upper() or "FIN" in pacType.upper(
        ):  #not SYN ACK since it will go to the first option
            pacTimer = Timer(
                Seconds(self.timeoutValue), self.timeout, sentPacket
            )  #self.timeoutValue = 10 :the RIP layer will wait for 10 seconds until resending the packet
            pacTimer.start()
            self.sentBoxData.append(
                (sentPacket.SeqNo, sentPacket, pacTimer,
                 False))  #packet seq, packet, timer, acked or not
            print("the packe is sent and next Seq number is:{}".format(
                sentPacket.SeqNo + len(sentPacket.Data)))

        elif "SYN" in pacType.upper(
        ) or "SYN" in pacType.upper() and "ACK" in pacType.upper():
            print("starting a SYN or SYN ACK handshake packets timer")
            self.sentHand = sentPacket
            self.timHand = Timer(Seconds(self.timeoutValue), self.timeout,
                                 self.sentHand)
            self.timHand.start()
            print("the timer object is: {}".format(self.timHand))
            print("the packe is sent from {} and next Seq number is:{}".format(
                self.identity, sentPacket.SeqNo + 1))

        for seq, packet, timer, acked in self.sentBoxData:
            print("sentBoxData:--- seq= {}, ack= {}, ACKED= {}".format(
                seq, seq + len(packet.Data), acked))

        #write packet
        serPacket = sentPacket.__serialize__()
        self.transport.write(sentPacket.__serialize__())
class RIP(StackingProtocol):
    def __init__(self):
        super().__init__()
        self.transport = None
        self.identity = None
        self.timeoutValue = 10  #the RIP layer will wait for 10 seconds until resending the packet
        self.SequenceNo = random.randrange(0, 101, 2)
        self.stateCon = 0  #open server
        self.sentBoxData = [
        ]  # tupple(Sequence Number, Packet object, Timer, Acked or Not)
        self.recieveBoxData = [
        ]  # tupple(Sequence Number, Packet object, Acked or Not)
        self.sentHand = None  #sent message from handshake
        self.recHand = None  #recieved message from hanshake
        self.timHand = None  #timer for hanshake
        self.firstCon = True  #first packet flag
        self.lastPacket = None  #lastPacket in order in the recieve end
        self._deserializer = RIPPacket.Deserializer()

    # 1 = SYN, 2 = ACK, 3 = FIN 4 = DATA
    def connection_made(self, transport):
        print("Received a connection from {}".format(
            transport.get_extra_info("peername")))
        self.transport = transport
        self.PassTransport = ATPtransport(self.transport, self)
        self.identity = "server"
        #import pdb; pdb.set_trace()
        print("im here in connection made in " + self.identity)
        #loop = asyncio.new_event_loop()
        #asyncio.set_event_loop(loop)

    def connection_lost(self, exc):
        # self.send("FIN", b"")
        # self.send("FIN", b"")
        # self.send("FIN", b"")#third time is the charm
        self.higherProtocol().connection_lost(exc)
        #loop = asyncio.get_event_loop()
        #loop.stop()

    def data_received(self, data):
        print("data_recieved start from " + self.identity)
        self._deserializer.update(data)

        for atppacket in self._deserializer.nextPackets():
            print(atppacket.Data)
            print("Got {} from the sender.".format(atppacket.Type))

            #check for doublicate and hash
            if self.recieveBoxData or self.recHand:
                if not self.checkPacket(atppacket):
                    print("error packet")
                    return

            #add to list
            print("recieved Type ={}, Seq= {}, ACK= {} ".format(
                atppacket.Type, atppacket.SeqNo, atppacket.AckNo))
            print("And the Connection is {}".format(self.stateCon))
            #end check

            #states: Connecring - 0, Ongoing - 1, Established - 2, FIN - 3
            if "SYN" in atppacket.Type and self.stateCon == 0:  #SYN SENT and Connection is open((server))
                self.handleHandshake(1, atppacket)

            elif "SYN" in atppacket.Type and "ACK" in atppacket.Type and self.stateCon == 1:  #SYN ACK and Connection is ongoing((client))
                print("the timer object is: {}".format(self.timHand))
                timerHandshake = self.timHand
                self.timHand.cancel()
                self.timHand = timerHandshake
                print("Timer is canceled")
                self.handleHandshake(2, atppacket)

            elif "ACK" in atppacket.Type:
                if self.stateCon == 3:
                    if self.sentBoxData[-1][0] + len(
                            self.sentBoxData[-1][1].Data) == atppacket.AckNo:
                        finTimer = self.sentBoxData[-1][2]
                        print("Timer is canceled")
                        finTimer.cancel()
                        self.sentBoxData[-1] = ((self.sentBoxData[-1][0],
                                                 self.sentBoxData[-1][1],
                                                 finTimer, True))
                        self.transport.close()

                if self.stateCon == 1:  #SYN ACK ACK and Connection is established((server))
                    print("the timer object is: {}".format(self.timHand))
                    timerHandshake = self.timHand
                    self.timHand.cancel()
                    self.timHand = timerHandshake
                    print("Timer is canceled")
                    self.handleHandshake(3, atppacket)

                elif self.stateCon == 2:
                    self.recieveAck(atppacket)
                    print("ACKnowledged")

            #the end of the handshake
            elif "DATA" in atppacket.Type.upper(
            ) and self.stateCon == 2:  #DATA and connection is established((serverANDclient))
                print("Got a packet {}".format(atppacket))
                self.recieveData(atppacket)

            elif "FIN" in atppacket.Type.upper(
            ) and self.stateCon == 2:  #FIN((server))
                print("Got a FIN packet {}".format(atppacket))
                self.stateCon = 3
                self.connection_lost("FIN")

                self.sendAck(atppacket)
                for n in range(len(self.recieveBoxData)):
                    if self.recieveBoxData[n][
                            2] is False and "DATA" in self.recieveBoxData[n][
                                1].Type.upper():  #Acked is True
                        return
                self.transport.close()  #close when you get an Ack for the fin

            else:
                print("the packet has a wrong type")
                if self.stateCon == 0:
                    self.transport.close()

    def handleHandshake(self, Type, handPacket):
        if Type == 1 and self.recHand is None:  #SYN
            self.recHand = handPacket
            self.send("SYN ACK", b"")  #SYN ACK
            self.stateCon = 1  #Ongoing
            #self.timHand.cancel()
            print("The connection is {}".format(self.stateCon))
            print("SYN and an ACK is sent,and the Ack number is  {}".format(
                handPacket.SeqNo + 1))

        elif Type == 2 and self.recHand is None:  #SYN ACK
            if handPacket.AckNo - 1 == self.sentHand.SeqNo:
                self.recHand = handPacket
                self.send("ACK", b"")  #SYN ACK ACK
                print(
                    "SYN:REC and an ACK is sent. The packet state is Established. The Ack number is{}"
                    .format(handPacket.SeqNo + 1))
                self.higherProtocol().connection_made(self.PassTransport)
                self.stateCon = 2  #established with server
                #self.timHand.cancel()
                print("\nconnection is made with server")
                self.SequenceNo = self.SequenceNo - 1  #for the first Data packet
            else:
                print("wrong SYN ACK")

        elif Type == 3 and "SYN" in self.recHand.Type:  #SYN ACK ACK
            if handPacket.AckNo - 1 == self.sentHand.SeqNo:
                self.recHand = handPacket
                print("Got SYN ACK ACK, and the sequence number is  {}".format(
                    handPacket.SeqNo))
                print("\nconnection is made with client")
                #self.timHand.cancel()
                self.higherProtocol().connection_made(
                    self.PassTransport)  #server connection
                self.stateCon = 2  #established
            else:
                print("wrong SYN ACK ACK")

    def recieveData(self, dataPacket):
        #add to the list
        self.recieveBoxData.append(
            (dataPacket.SeqNo, dataPacket, False))  #Acked is false
        #sort
        self.recieveBoxData.sort()
        #print the list
        indexx = 0
        completeFlag = True
        for seq, packet, acked in self.recieveBoxData:
            print("recieveBoxList:----Seq= {}, Acked= {}, Next= {}".format(
                seq, acked, seq + len(packet.Data)))

            if acked is False and packet.Type.upper() == "DATA":
                completeFlag = False

        if dataPacket.Type == "FIN" and completeFlag:
            self.sendAck(dataPacket)
            self.transport.close()

        print("Number of Packets are: {}".format(len(self.recieveBoxData)))
        #send to higher protocol and remove packets
        appData = b""
        index = 1
        if len(self.recieveBoxData) != 1:
            for index in range(len(self.recieveBoxData)):
                pefIndex = index - 1
                #if self.recieveBoxData[index][2] is False and self.recieveBoxData[index][0] == self.recieveBoxData[pefIndex][0] + len(self.recieveBoxData[pefIndex][1].Data):
                if self.recieveBoxData[index][
                        2] is False and self.recieveBoxData[index][0] == (
                            self.recieveBoxData[pefIndex][0] +
                            len(self.recieveBoxData[pefIndex][1].Data)
                        ) and self.recieveBoxData[pefIndex][2]:
                    #send current packet data to application
                    self.lastPacket = self.recieveBoxData[index][1]
                    self.recieveBoxData[index] = (
                        self.recieveBoxData[index][0],
                        self.recieveBoxData[index][1], True
                    )  #because tuples dont support update, so reassigment to the index with Acked True
                    print(" A: This acked packet seq no is {}".format(
                        self.recieveBoxData[index][0]))
                    appData = appData + self.recieveBoxData[index][
                        1].Data  #add data
                    #index = index + 1
        else:
            self.recieveBoxData[0] = (self.recieveBoxData[0][0],
                                      self.recieveBoxData[0][1], True)
            self.lastPacket = self.recieveBoxData[0][1]
            appData = self.lastPacket.Data
        #acked all data packets
        self.sendAck(self.lastPacket)
        #print

        # #send data to the application layer
        self.higherProtocol().data_received(appData)

    def recieveAck(self, ackPacket):
        #packetIndex = 0
        for Seq, dataPacket, timer, acked in self.sentBoxData:
            print(
                "SentBoxList:---- for Seq= {}, Data packet ACK= {}, Acked= {} and recieved ACK is= {}"
                .format(Seq, Seq + len(dataPacket.Data), acked,
                        ackPacket.AckNo))
            if (
                    Seq + len(dataPacket.Data)
            ) == ackPacket.AckNo and acked is False:  #if the ack matches the list value
                print("It's a match with a sent packet= {}".format(Seq))
                packetIndex = self.sentBoxData.index(
                    (Seq, dataPacket, timer, acked
                     )) + 1  #index starts with 0, while range starts with 1
                print("the packet index is= {}".format(packetIndex))
                for n in range(
                        packetIndex
                ):  #find the timer in the dictionary using the seq number
                    #cancel all the timer less than the seq number
                    currentTimer = self.sentBoxData[n][2]  #timer cancelation
                    currentTimer.cancel()
                    print("timer is canceled")
                    self.sentBoxData[n] = (self.sentBoxData[n][0],
                                           self.sentBoxData[n][1],
                                           currentTimer, True)
                    #self.timerDict[packetSeq] = timer.cancel()
                return

    def checkPacket(self, packet):
        #loop dic if exist send from to last acked packet and check doublications
        if "DATA" in packet.Type.upper():
            for packetSeq, DataPacket, acked in self.recieveBoxData:
                if packetSeq == packet.SeqNo:
                    if acked is True:
                        self.sendAck(
                            DataPacket)  #acked data packet, resend ACK
                        print(
                            "resending ACK since the packet is already acked by the protocol"
                        )
                        return False
                    elif acked is False:  #for doubliction Data packets
                        print("double Data packets is recieved")
                        return False

        #check Hash
        checkedHash = self.hashPacket(packet)
        print("Checked Checksum is: " + checkedHash.decode())
        if packet.CRC != checkedHash:
            print("the packet has been modefied")
            return False
        return True

    def hashPacket(self, hashPacket):
        print("start hashing")
        ATPpacket = RIPPacket(Type=hashPacket.Type,
                              SeqNo=hashPacket.SeqNo,
                              AckNo=hashPacket.AckNo,
                              CRC=b"",
                              Data=hashPacket.Data)
        checksum = hashlib.sha256(ATPpacket.__serialize__()).hexdigest()
        checksum = checksum.encode()
        return checksum

    def sendAck(self, packetAck):
        sentAck = RIPPacket()
        #add Ack number
        sentAck.AckNo = packetAck.SeqNo + len(
            packetAck.Data
        )  #sequence number and data length of previouse recieved packet
        #add Seq
        sentAck.SeqNo = 0
        #add Type
        sentAck.Type = "ACK"
        #add Data
        sentAck.Data = b""
        #add checksum
        sentAck.CRC = self.hashPacket(sentAck)
        print("checksum is: {}".format(sentAck.CRC.decode()))
        print("send Type ={}, Seq= {}, ACK= {}".format(sentAck.Type,
                                                       sentAck.SeqNo,
                                                       sentAck.AckNo))
        #add packet to the sent list
        self.transport.write(sentAck.__serialize__())
        print("the ACK is sent for: {}".format(sentAck.AckNo))

    def send(self, pacType, PacData):
        sentPacket = RIPPacket()
        print("the packet type is: {}".format(pacType))
        #calculateSeqAck
        if "SYN" in pacType.upper() and "ACK" in pacType.upper():
            print("SYN ACK")
            #add Ack number
            sentPacket.AckNo = self.recHand.SeqNo + 1
            #add Seq
            sentPacket.SeqNo = self.SequenceNo  #random seq

        elif "ACK" in pacType.upper():
            if self.stateCon == 1:
                print("1 ACK")
                #add Ack number
                sentPacket.AckNo = self.recHand.SeqNo + 1
                #add Seq
                sentPacket.SeqNo = self.sentHand.SeqNo + 1

        elif "SYN" in pacType.upper():
            print("SYN")
            #add Ack number
            sentPacket.AckNo = 0
            #add Seq
            sentPacket.SeqNo = self.SequenceNo  #random seq

        elif "DATA" in pacType.upper() or "FIN" in pacType.upper():
            if self.sentHand is not None:
                print("1st Packet after the Handshake")
                #add Ack number
                sentPacket.AckNo = 0
                #add Seq
                sentPacket.SeqNo = self.recHand.AckNo
                #empty hands
                self.recHand = None
                self.sentHand = None
            else:
                #add Ack number
                sentPacket.AckNo = 0
                #add Seq
                sentPacket.SeqNo = self.sentBoxData[-1][0] + len(
                    self.sentBoxData[-1][1].Data
                )  #sequence number and data length of previouse sent packet

            if "FIN" in pacType.upper():
                self.stateCon = 3  #FIN state
        else:
            print("IM NOTHING{}".format(sentPacket.AckNo))

        #add Type
        sentPacket.Type = pacType

        #add Data
        sentPacket.Data = PacData

        #add checksum
        sentPacket.CRC = self.hashPacket(sentPacket)
        print("checksum is: {}".format(sentPacket.CRC.decode()))
        print("send Type ={}, Seq= {}, ACK= {}".format(sentPacket.Type,
                                                       sentPacket.SeqNo,
                                                       sentPacket.AckNo))
        #add packet to the sent list

        if "DATA" in pacType.upper() or "FIN" in pacType.upper(
        ):  #not SYN ACK since it will go to the first option
            pacTimer = Timer(
                Seconds(self.timeoutValue), self.timeout, sentPacket
            )  #self.timeoutValue = 10 :the RIP layer will wait for 10 seconds until resending the packet
            pacTimer.start()
            self.sentBoxData.append(
                (sentPacket.SeqNo, sentPacket, pacTimer,
                 False))  #packet seq, packet, timer, acked or not
            print("the packe is sent and next Seq number is:{}".format(
                sentPacket.SeqNo + len(sentPacket.Data)))

        elif "SYN" in pacType.upper(
        ) or "SYN" in pacType.upper() and "ACK" in pacType.upper():
            print("starting a SYN or SYN ACK handshake packets timer")
            self.sentHand = sentPacket
            self.timHand = Timer(Seconds(self.timeoutValue), self.timeout,
                                 self.sentHand)
            self.timHand.start()
            print("the timer object is: {}".format(self.timHand))
            print("the packe is sent from {} and next Seq number is:{}".format(
                self.identity, sentPacket.SeqNo + 1))

        for seq, packet, timer, acked in self.sentBoxData:
            print("sentBoxData:--- seq= {}, ack= {}, ACKED= {}".format(
                seq, seq + len(packet.Data), acked))

        #write packet
        serPacket = sentPacket.__serialize__()
        self.transport.write(sentPacket.__serialize__())

    def resend(self, resntPacket):
        if "DATA" in resntPacket.Type.upper():  #start timer again
            #get timer
            for seq, packet, timer, acked in self.sentBoxData:
                if seq == resntPacket.SeqNo:
                    timer.cancel()
                    index = self.sentBoxData.index((seq, packet, timer, acked))
                    pacTimer = Timer(Seconds(self.timeoutValue), self.timeout,
                                     packet)
                    pacTimer.start()
                    self.sentBoxData[index] = (
                        seq, packet, pacTimer, False
                    )  #packet seq, packet, timer, acked or not
                    #start timer
        elif "FIN" in resntPacket.Type.upper():
            currentTimer = self.sentBoxData[-1][2]
            currentTimer.cancel()
            currentTimer = Timer(Seconds(self.timeoutValue), self.timeout,
                                 self.sentBoxData[-1][1])
            currentTimer.start()
            self.sentBoxData[-1] = (self.sentBoxData[-1][0],
                                    self.sentBoxData[-1][1], currentTimer,
                                    False)  #last packet since its FIN
        elif "ACK" in resntPacket.Type.upper():
            if "SYN" in resntPacket.Type.upper():
                self.timHand.cancel()
            self.timHand = Timer(Seconds(self.timeoutValue), self.timeout,
                                 self.sentHand)
            self.timHand.start()

        elif "SYN" in resntPacket.Type.upper():
            self.stateCon = 0
            print("Im here")
            self.timHand.cancel()
            self.timHand = Timer(Seconds(self.timeoutValue), self.timeout,
                                 self.sentHand)
            self.timHand.start()

        resendPacket = RIPPacket(Type=resntPacket.Type,
                                 SeqNo=resntPacket.SeqNo,
                                 AckNo=resntPacket.AckNo,
                                 CRC=resntPacket.CRC,
                                 Data=resntPacket.Data)
        print("resend packet: Type = {}, SeqNo = {}, AckNo = {},\n CRC = {}".
              format(resntPacket.Type, resntPacket.SeqNo, resntPacket.AckNo,
                     resntPacket.CRC.decode()))
        self.transport.write(resendPacket.__serialize__())

    def timeout(self, timedPacket):
        #import pdb; pdb.set_trace()
        print("\ntimeout\nresend packet {} to {}".format(
            timedPacket.SeqNo, self.identity))
        self.resend(timedPacket)