Example #1
0
    def __init__(self, window_size = 10, verbose = False):
        self.window_size = window_size
        self.window = {}
        self.sequence_number = 0
        self.retransmit_timer = RetransmitTimer()
        self.io_loop = IOLoop()
        self.logger = logging.getLogger('mf_socket')

        self.terminator_packet_num_sent = 0
        self.terminator_packet_seq_num = 0

        if verbose:
            self.logger.setLevel(10)
        else:
            self.logger.setLevel(0)
    def __init__(self, window_size=10, debugging=False):
        self.window_size = window_size
        self.io = IOLoop()
        self.cxn_status = RxPConnectionStatus.NONE
        self.retransmit_timer = RetransmitTimer()

        # for python module logging msgs.. enable if debugger param toggled
        self.logger = logging.getLogger('rxp_socket')
        self.logger.setLevel(0)
        if debugging:
            self.logger.setLevel(10)

        self.destination = None
        self.port_number = None

        self.seq_number = 0
        self.ack_number = 0
class RxPSocket:
    def __init__(self, window_size=10, debugging=False):
        self.window_size = window_size
        self.io = IOLoop()
        self.cxn_status = RxPConnectionStatus.NONE
        self.retransmit_timer = RetransmitTimer()

        # for python module logging msgs.. enable if debugger param toggled
        self.logger = logging.getLogger('rxp_socket')
        self.logger.setLevel(0)
        if debugging:
            self.logger.setLevel(10)

        self.destination = None
        self.port_number = None

        self.seq_number = 0
        self.ack_number = 0

    """
    Takes in src address and binds UDP socket to specified port.
    """

    def bind(self, address):
        if address:
            self.port_number = address[1]
            self.io.socket.bind(address)

    """
    For server to accept new client socket.
    """
    def accept(self):
        syn_received = False
        ack_received = False

        # NOTE: starts thread's activity. arranges for the run() method to be invoked on a separate thread of control
        if not self.io.isAlive():
            self.io.start()

        # wait for a syn that passes verification
        while not syn_received:
            try:
                # NOTE: 1st param blocks, 2nd is timeout (on queue.get)
                syn_packet, self.destination = self.io.recv_queue.get(True, 1)
            except Queue.Empty:
                continue

            if syn_packet and self.destination:
                syn_received = self.__verify_syn(syn_packet, self.destination)

        # send SYN/ACK
        self.logger.debug('Received SYN during handshake; sending SYN/ACK to progress handshake.')
        syn_ack_packet = RxPPacket(
            self.port_number,
            self.destination[1],
            ack_number=syn_packet.seq_number + 1,  # use SYN recvd seq number for ACK
            ack=True,
            syn=True
        )

        self.io.send_queue.put((syn_ack_packet, self.destination))
        self.seq_number += 1

        # wait for ACK from client confirming SYN/ACK received
        while not ack_received:
            try:
                ack_packet, address = self.io.recv_queue.get(True, 1)
            except Queue.Empty:
                self.logger.debug('Timed out waiting on ack during handshake; retransmitting SYN/ACK.')
                syn_ack_packet.frequency += 1
                syn_ack_packet.update_checksum()
                self.io.send_queue.put((syn_ack_packet, self.destination))
                continue

            if ack_packet and address:
                ack_received = self.__verify_ack(ack_packet, address, syn_ack_packet.seq_number)
                if ack_received:
                    self.logger.debug('Received ACK during handshake; client socket accepted')

        self.cxn_status = RxPConnectionStatus.IDLE

    """
    For client to attempt to connect to a server.
    """
    def connect(self, dst_adr):
        self.destination = dst_adr
        syn_ack_received = False
        self.io.start()

        # send SYN
        self.logger.debug('Sending SYN to initiate handshake.')
        syn_packet = RxPPacket(
            self.port_number,
            self.destination[1],
            seq_number=self.seq_number,
            syn=True
        )
        self.io.send_queue.put((syn_packet, self.destination))
        self.seq_number += 1
        ack_sent = False
        ack_confirmed = False
        syn_ack_timeout = 1

        # wait for SYN/ACK
        while not (syn_ack_received and ack_confirmed):
            syn_ack_packet = None
            try:
                syn_ack_packet, address = self.io.recv_queue.get(True, syn_ack_timeout)
            except Queue.Empty:
                if syn_ack_packet == None and ack_sent:
                    ack_confirmed = True
                    break

                self.logger.debug('Timed out waiting on SYN/ACK during handshake; retransmitting SYN.')
                syn_packet.frequency += 1
                syn_packet.update_checksum()
                self.io.send_queue.put((syn_packet, self.destination))
                continue

            if syn_ack_packet and address:
                syn_ack_received = self.__verify_syn_ack(syn_ack_packet, address, syn_packet.seq_number)

                if syn_ack_received:
                    self.logger.debug('Received SYN/ACK during handshake; sending ACK to finish handshake.')
                    ack_sent = True
                    syn_ack_timeout = 4
                    ack_packet = RxPPacket(
                        self.port_number,
                        self.destination[1],
                        seq_number=self.seq_number,
                        ack_number=syn_ack_packet.seq_number + 1,
                        ack=True
                    )
                    self.io.send_queue.put((ack_packet, self.destination))

        self.seq_number += 1
        self.cxn_status = RxPConnectionStatus.IDLE

    """
    For client or server to send a msg. The 'kill_packet' is used
    to inform client and server can know when we done sending.
    """
    def send(self, msg):
        floor = 0
        payload_size = 512
        packets = []

        # chunk data into packets
        while floor < len(msg):
            if floor + payload_size <= len(msg):
                payload = msg[floor: floor + payload_size]
            else:
                payload = msg[floor:]

            data_packet = RxPPacket(
                self.port_number,
                self.destination[1],
                seq_number=self.seq_number,
                payload=payload
            )
            packets.append(data_packet)
            self.seq_number += 1
            floor += payload_size

        kill_packet = RxPPacket(
            self.port_number,
            self.destination[1],
            seq_number=self.seq_number
        )
        kills_sent = 0  # allow to be sent 3 times before dropping client cxn
        kill_seq_number = kill_packet.seq_number
        packets.append(kill_packet)  # put that shit at the end after we've added all the other packets
        self.seq_number += 1

        self.logger.debug('Placing packets in window to be sent now...')
        window = SlidingWindow(packets, self.window_size)
        time_sent = time.time()
        time_remaining = self.retransmit_timer.timeout

        self.cxn_status = RxPConnectionStatus.SEND
        for data_packet in window.window:
            self.io.send_queue.put((data_packet, self.destination))

        while not window.is_empty():
            try:
                ack_packet, address = self.io.recv_queue.get(True, time_remaining)

            # resend entire send window (all packets that weren't yet ACK'd by the receiver)
            except Queue.Empty:
                self.logger.debug(
                    'Timed out waiting for ack during data transmission; retransmitting unacknowledged packets.')
                time_sent = time.time()
                time_remaining = self.retransmit_timer.timeout

                for data_packet in window.window:
                    if kill_seq_number == data_packet.seq_number:
                        kills_sent += 1
                        if kills_sent > 3:  # if retransmitted 3 times already, kill cxn with client
                            self.logger.debug(
                                'Kill packet failed to be acknowledged; unable to end connection, closing now.')
                            return

                    if not window.acknowledged_packets.get(data_packet.seq_number):
                        data_packet.frequency += 1
                        data_packet.update_checksum()
                        self.io.send_queue.put((data_packet, self.destination))
                continue

            # if still getting SYN/ACK, retransmit ACK
            if self.__verify_syn_ack(ack_packet, address, 1):
                self.logger.debug('Received SYN/ACK retransmission; retransmitting ACK.')
                ack_packet = RxPPacket(
                    self.port_number,
                    self.destination[1],
                    ack_number=ack_packet.seq_number + 1,
                    seq_number=2,
                    ack=True
                )
                self.io.send_queue.put((ack_packet, self.destination))
                time_remaining = 0

            # if a packet in window is acknowledged, slide the window past said received packet
            elif self.__verify_is_ack(ack_packet, address) and window.index_of_packet(ack_packet) >= 0:
                self.retransmit_timer.update(ack_packet.frequency, time.time() - time_sent)
                self.logger.debug(
                    'ACK received. Updated retransmit timer; timeout is now ' + str(self.retransmit_timer.timeout))
                window.acknowledge_packet(ack_packet)

                if self.__verify_ack(ack_packet, address, window.window[0].seq_number):
                    additions = window.slide()
                    # send newly added packets if they were added
                    if additions > 0:
                        while additions > 0:
                            self.io.send_queue.put((window.window[-additions], self.destination))
                            self.seq_number += 1
                            additions -= 1

            # otherwise, update time remaining
            else:
                time_remaining -= time.time() - time_sent / 4  # decay
                if time_remaining < time.time():
                    time_remaining = .5
                self.logger.debug('Trash packet receive; time remaining before next timeout: ' + str(time_remaining))

        self.cxn_status = RxPConnectionStatus.IDLE

    def recv(self):
        kill_received = False
        read_kill = False
        packets = {}
        frequencies = {}

        self.cxn_status = RxPConnectionStatus.RECV
        # until connection is closed, read data
        while not read_kill:
            try:
                data_packet, address = self.io.recv_queue.get(True, 1)
            except Queue.Empty:
                if self.cxn_status == RxPConnectionStatus.CLSG:
                    break
                continue

            if address == self.destination:
                if frequencies.get(data_packet.seq_number):
                    frequencies[data_packet.seq_number] += 1
                else:
                    frequencies[data_packet.seq_number] = 1

                packets[data_packet.seq_number] = data_packet

                # if we got a fin, send fin ack back
                if data_packet.fin:
                    self.logger.debug('Sending FIN/ACK during data transfer.')
                    fin_ack_packet = RxPPacket(
                        self.port_number,
                        self.destination[1],
                        seq_number=self.seq_number,
                        ack_number=data_packet.seq_number + 1,
                        frequency=frequencies[data_packet.seq_number],
                        ack=True,
                        fin=True
                    )
                    self.io.send_queue.put((fin_ack_packet, self.destination))
                    self.seq_number += 1
                    self.cxn_status = RxPConnectionStatus.CLSG

                # if we get an ack while closing, we've gracefully closed
                elif data_packet.ack and self.cxn_status == RxPConnectionStatus.CLSG:
                    self.logger.debug('Received Final ACK. Closing..')
                    self.cxn_status = RxPConnectionStatus.NONE
                    return "CONNECTION CLOSED"

                else:
                    self.logger.debug('Sending ACK during data transfer.')
                    ack_packet = RxPPacket(
                        self.port_number,
                        self.destination[1],
                        seq_number=self.seq_number,
                        ack_number=data_packet.seq_number + 1,
                        frequency=frequencies[data_packet.seq_number],
                        ack=True
                    )
                    self.io.send_queue.put((ack_packet, self.destination))
                    self.seq_number += 1

                if data_packet.is_killer():
                    kill_received = True
                    self.logger.debug('Kill packet detected.')

                if kill_received:
                    sorted_pkeys = sorted(packets.keys())
                    read_kill = sorted_pkeys == range(sorted_pkeys[0], sorted_pkeys[0] + len(sorted_pkeys))

        response = ''.join(
            map(
                lambda packet: packet.payload,
                map(lambda sequence_number: packets[sequence_number], sorted(packets.keys()))
            ))
        self.cxn_status = RxPConnectionStatus.IDLE
        return response

    def close(self):
        clean_close = False

        self.logger.debug('Sending FIN to initiate close.')
        fin_packet = RxPPacket(
            self.port_number,
            self.destination[1],
            seq_number=self.seq_number,
            fin=True
        )
        self.io.send_queue.put((fin_packet, self.destination))
        fins_sent = 1
        self.seq_number += 1

        while not clean_close:
            try:
                fin_response_packet, address = self.io.recv_queue.get(True, 1)
            except Queue.Empty:
                if fins_sent < 3:
                    self.logger.debug('Timed out waiting for FIN/ACK during close; sending another FIN.')
                    fin_packet = RxPPacket(
                        self.port_number,
                        self.destination[1],
                        seq_number=self.seq_number,
                        fin=True
                    )
                    self.io.send_queue.put((fin_packet, self.destination))
                    fins_sent += 1
                    continue
                else:
                    self.logger.debug(
                        'Timed out waiting for FIN/ACK during close. Already attempted to close 3 times, closing now without acknowledgement.')
                    self.cxn_status = RxPConnectionStatus.NONE
                    break

            # if FIN received after FIN sent, verify with ACK and close
            if self.__verify_fin(fin_response_packet, address):
                clean_close = True
                self.logger.debug('Received FIN during close; sending ACK to finish close.')
                ack_packet = RxPPacket(
                    self.port_number,
                    self.destination[1],

                    seq_number=self.seq_number,
                    ack_number=fin_response_packet.seq_number + 1,
                    ack=True
                )
                self.io.send_queue.put((ack_packet, self.destination))
                self.seq_number += 1
                time.sleep(5)
                self.cxn_status = RxPConnectionStatus.NONE

                # received ACK for FIN sent, so FIN packet sent corrupted, resend fin packet
            if self.__verify_ack(fin_response_packet, address, fin_packet.seq_number):
                self.logger.debug('Received ACK for FIN during close; resending FIN to progress close.')
                self.io.send_queue.put((fin_packet, self.destination))

                # if FIN/ACK received then progress with closing handshake
            if self.__verify_fin_ack(fin_response_packet, address, fin_packet.seq_number):
                clean_close = True
                self.logger.debug('Received FIN/ACK during close; sending ACK to finish close.')
                ack_packet = RxPPacket(
                    self.port_number,
                    self.destination[1],
                    seq_number=self.seq_number,
                    ack_number=fin_response_packet.seq_number + 1,
                    ack=True
                )
                self.io.send_queue.put((ack_packet, self.destination))
                self.seq_number += 1
                time.sleep(5)
                self.cxn_status = RxPConnectionStatus.NONE

    def __verify_syn(self, packet, address):
        return address == self.destination and packet.syn

    def __verify_is_ack(self, packet, address):
        return address == self.destination and packet.ack

    def __verify_ack(self, packet, address, sequence_number):
        return address == self.destination and packet.ack and packet.ack_number - 1 == sequence_number

    def __verify_syn_ack(self, packet, address, sequence_number):
        return address == self.destination and packet.syn and packet.ack and packet.ack_number - 1 == sequence_number

    def __verify_fin_ack(self, packet, address, sequence_number):
        return address == self.destination and packet.fin and packet.ack and packet.ack_number - 1 == sequence_number

    def __verify_fin(self, packet, address):
        return address == self.destination and packet.fin and not packet.ack
Example #4
0
class MFSocket:
    def __init__(self, window_size = 10, verbose = False):
        self.window_size = window_size
        self.window = {}
        self.sequence_number = 0
        self.retransmit_timer = RetransmitTimer()
        self.io_loop = IOLoop()
        self.logger = logging.getLogger('mf_socket')

        self.terminator_packet_num_sent = 0
        self.terminator_packet_seq_num = 0

        if verbose:
            self.logger.setLevel(10)
        else:
            self.logger.setLevel(0)

    def mf_assign(self, port_number):
        self.port_number = port_number

    def mf_bind(self, address):
        self.port_number = address[1]
        self.io_loop.socket.bind(address)

    def mf_accept(self):
        syn_received = False
        ack_received = False

        self.io_loop.start()

        # wait for syn
        while not syn_received:
            try:
                syn_packet, self.destination = self.io_loop.receive_queue.get(True, 1)
            except Queue.Empty:
                continue

            syn_received = self.__verify_syn(syn_packet, self.destination)

        # send syn/ack
        self.logger.debug('received syn during handshake. sending syn/ack to progress handshake.')
        syn_ack_packet = MFPacket(
            self.port_number,
            self.destination[1],
            ack_number = syn_packet.sequence_number + 1,
            ack = True,
            syn = True
        )
        self.io_loop.send_queue.put((syn_ack_packet, self.destination))
        self.sequence_number += 1

        # wait for ack, retransmit on timeout
        while not ack_received:
            try:
                ack_packet, address = self.io_loop.receive_queue.get(True, 1)
            except Queue.Empty:
                self.logger.debug('timed out waiting on ack during handshake. retransmitting syn/ack.')
                syn_ack_packet.frequency += 1
                syn_ack_packet.recalculate_checksum()
                self.io_loop.send_queue.put((syn_ack_packet, self.destination))
                continue

            if self.__verify_ack(ack_packet, address, syn_ack_packet.sequence_number):
                ack_received = True
                self.logger.debug('received ack during handshake.')

    def mf_connect(self, address):
        self.destination = address
        syn_ack_received = False

        self.io_loop.start()

        # send syn
        self.logger.debug('sending syn to initiate handshake.')
        syn_packet = MFPacket(
            self.port_number,
            self.destination[1],
            sequence_number = self.sequence_number,
            syn = True
        )
        self.io_loop.send_queue.put((syn_packet, self.destination))
        self.sequence_number += 1

        # wait for syn/ack, retransmit on timeout
        while not syn_ack_received:
            try:
                syn_ack_packet, address = self.io_loop.receive_queue.get(True, 1)
            except Queue.Empty:
                self.logger.debug('timed out waiting on syn/ack during handshake. retransmitting syn.')
                syn_packet.frequency += 1
                syn_packet.recalculate_checksum()
                self.io_loop.send_queue.put((syn_packet, self.destination))
                continue

            syn_ack_received = self.__verify_syn_ack(syn_ack_packet, address, syn_packet.sequence_number)

        # send ack
        self.logger.debug('received syn/ack during handshake. sending ack to finish handshake.')
        ack_packet = MFPacket(
            self.port_number,
            self.destination[1],
            ack_number = syn_ack_packet.sequence_number + 1,
            sequence_number = self.sequence_number,
            ack = True
        )
        self.io_loop.send_queue.put((ack_packet, self.destination))
        self.sequence_number += 1

    def mf_write(self, data):
        start = 0
        payload_size = 512
        packets = []

        # chunk data into packets
        while start < len(data):
            if start + payload_size <= len(data):
                payload = data[start : start + payload_size]
            else:
                payload = data[start :]

            data_packet = MFPacket(
                self.port_number,
                self.destination[1],
                sequence_number = self.sequence_number,
                payload = payload
            )
            packets.append(data_packet)
            self.sequence_number += 1
            start += payload_size

        terminator_packet = MFPacket(
            self.port_number,
            self.destination[1],
            sequence_number = self.sequence_number
        )
        packets.append(terminator_packet)
        self.terminator_packet_seq_num = self.sequence_number
        self.terminator_packet_num_sent = 0
        self.sequence_number += 1

        # populate window and send all packets
        window = SlidingWindow(packets, self.window_size)

        last_sent = time.time()
        time_remaining = self.retransmit_timer.timeout
        self.logger.debug('sending data packets in window.')
        for data_packet in window.window:
            self.io_loop.send_queue.put((data_packet, self.destination))
            #print data_packet.data_offset

        while not window.is_empty():
            try:
                # wait for incoming packet
                ack_packet, address = self.io_loop.receive_queue.get(True, time_remaining)
            except Queue.Empty:
                # timeout, go back n
                self.logger.debug('timed out waiting for ack during data transmission. retransmitting window.')
                last_sent = time.time()
                time_remaining = self.retransmit_timer.timeout

                for data_packet in window.window:

                    if self.terminator_packet_seq_num == data_packet.sequence_number:
                        self.terminator_packet_num_sent += 1
                        if self.terminator_packet_num_sent > 3:
                            self.logger.debug('Unable to end connection, terminating now')
                            return

                    data_packet.frequency += 1
                    data_packet.recalculate_checksum()
                    self.io_loop.send_queue.put((data_packet, self.destination))



                continue

            # if still getting syn/ack, retransmit ack
            if self.__verify_syn_ack(ack_packet, address, 1):
                self.logger.debug('received syn/ack retransmission. retransmitting ack.')
                ack_packet = MFPacket(
                    self.port_number,
                    self.destination[1],
                    ack_number = ack_packet.sequence_number + 1,
                    sequence_number = 2,
                    ack = True
                )
                self.io_loop.send_queue.put((ack_packet, self.destination))
                time_remaining = 0
            # if first packet in pipeline is acknowledged, slide the window
            elif self.__verify_ack(ack_packet, address, window.window[0].sequence_number):
                self.retransmit_timer.update(ack_packet.frequency, time.time() - last_sent)
                self.logger.debug('updated retransmit timer. timeout is now ' + str(self.retransmit_timer.timeout))
                window.slide()
                if not window.is_emptying():
                    self.io_loop.send_queue.put((window.window[-1], self.destination))
                    self.sequence_number += 1
                    #print "executing"
            # otherwise, update time remaining
            else:
                time_remaining -= time.time() - last_sent/4
                if time_remaining < time.time():
                    time_remaining = .5
                self.logger.debug('bunk packet received. time remaining before timeout: ' + str(time_remaining))

    def mf_read(self):
        terminator_received = False
        read_terminated = False
        packets = {}
        frequencies = {}

        # until connection is closed, read data
        while not read_terminated:
            try:
                data_packet, address = self.io_loop.receive_queue.get(True, 1)
                #print data_packet.payload
            except Queue.Empty:
                continue

            if address == self.destination:
                if frequencies.get(data_packet.sequence_number):
                    frequencies[data_packet.sequence_number] += 1
                else:
                    frequencies[data_packet.sequence_number] = 1
                #print data_packet.sequence_number

                packets[data_packet.sequence_number] = data_packet
                self.logger.debug('sending ack during data transfer.')
                ack_packet = MFPacket(
                    self.port_number,
                    self.destination[1],
                    sequence_number = self.sequence_number,
                    frequency = frequencies[data_packet.sequence_number],
                    ack = True,
                    ack_number = data_packet.sequence_number + 1
                )
                self.io_loop.send_queue.put((ack_packet, self.destination))
                self.sequence_number += 1

                if data_packet.is_terminator():
                    terminator_received = True
                    self.logger.debug('terminator packet detected.')

                if terminator_received:
                    sorted_keys = sorted(packets.keys())
                    read_terminated = sorted_keys == range(sorted_keys[0], sorted_keys[0] + len(sorted_keys))
        #for key in packets.keys():
        #    print packets[key].payload
        #print "Packet.keys length: " + str(len(packets.keys()))
        return ''.join(map(lambda packet: packet.payload, map(lambda sequence_number: packets[sequence_number], sorted(packets.keys()))))

    def mf_close(self):
        fin_ack_received = False

        self.logger.debug('sending fin to initiate close.')
        fin_packet = MFPacket(
            self.port_number,
            self.destination[1],
            sequence_number = self.sequence_number,
            fin = True
        )
        self.io_loop.send_queue.put((fin_packet, self.destination))
        self.sequence_number += 1

        while not fin_ack_received:
            try:
                fin_ack_packet, address = self.io_loop.receive_queue.get(True, 1)
            except Queue.Empty:
                self.logger.debug('timed out waiting for fin/ack during close. closing.')
                break

            if self.__verify_fin_ack(fin_ack_packet, address, fin_packet.sequence_number):
                fin_ack_received = True
                self.logger.debug('received fin/ack during close. sending ack to finish close.')
                ack_packet = MFPacket(
                    self.port_number,
                    self.destination[1],
                    sequence_number = self.sequence_number,
                    ack = True,
                    ack_number = fin_ack_packet.sequence_number + 1
                )
                self.io_loop.send_queue.put((ack_packet, self.destination))
                self.sequence_number += 1

    def __close(self, ack_number):
        ack_received = False

        self.logger.debug('sending fin/ack to progress close.')
        fin_ack_packet = MFPacket(
            self.port_number,
            self.destination[1],
            sequence_number = self.sequence_number,
            fin = True,
            ack = True,
            ack_number = ack_number
        )
        self.io_loop.send_queue.put((fin_ack_packet, self.destination))
        self.sequence_number += 1

        while not ack_received:
            try:
                ack_packet, address = self.io_loop.receive_queue.get(True, 1)
            except Queue.Empty:
                self.logger.debug('timed out waiting for ack during close. closing.')
                break

            if self.__verify_ack(ack_packet, address, fin_ack_packet.sequence_number):
                ack_received = True
                self.logger.debug('recieved ack during close. closing')

    def __verify_syn(self, packet, address):
        return address == self.destination and packet.syn

    def __verify_ack(self, packet, address, sequence_number):
        return address == self.destination and packet.ack and packet.ack_number - 1 == sequence_number

    def __verify_syn_ack(self, packet, address, sequence_number):
        return address == self.destination and packet.syn and packet.ack and packet.ack_number - 1 == sequence_number

    def __verify_fin_ack(self, packet, address, sequence_number):
        return address == self.destination and packet.fin and packet.ack and packet.ack_number - 1 == sequence_number