Example #1
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()
Example #2
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()
    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__())
Example #4
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()
Example #5
0
File: PEEP.py Project: sbw111/lab4
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 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)