Пример #1
0
    def connect(
            self,
            remote_address):  # real signature unknown; restored from __doc__
        """
        connect(address)

        Connect the socket to a remote address.  For IP sockets, the address
        is a pair (host, port).
        """

        # init remote_address
        self.__remote_address = remote_address

        # connect to IP layer
        print('connecting to IP layer')
        self.__ip = IP.IP(IP.PROTOCOL_TCP,
                          self.__local_address[0],
                          dst_ip=remote_address[0])
        print('connected to IP layer')

        # generate client_isn
        self.__isn = random.randint(0, 2147483645)
        client_isn = self.__isn
        print('generated isn', self.__isn)

        # build a tcp object with SYN
        tcp = TCP()
        tcp.build(type=tcp.SEND_SYN,
                  src_port=self.__local_address[1],
                  dst_port=remote_address[1],
                  sequence_number=self.__isn)

        # sign a space in buffer_list
        buffer_list['connecting'][remote_address] = []

        # sent tcp object
        self.__ip.send(bytes(tcp))
        print('sent tcp object')

        # record first_package_sent_time
        first_package_sent_time = time.time()

        # wait for sencond hanshake
        print('waiting for sencond hanshake')
        star_time = time.time()
        flag_3 = True
        flag_6 = False
        flag_12 = False

        while buffer_list['connecting'][remote_address] == []:
            if flag_3 and time.time() - star_time >= 2:
                print('3s timeout')
                self.__ip.send(bytes(tcp))
                flag_3 = False
                flag_6 = True
                star_time = time.time()
            elif flag_6 and time.time() - star_time >= 2:
                print('6s timeout')
                self.__ip.send(bytes(tcp))
                flag_6 = False
                flag_12 = True
                star_time = time.time()
            elif flag_12 and time.time() - star_time >= 2:
                print('12s timeout')
                self.__ip.send(bytes(tcp))
                flag_12 = False
                star_time = time.time()
            elif time.time() - star_time >= 4:
                print('break')
                return
            continue

        self.status = 'established'
        # record first_package_receive_time
        self.__sample_RTT = time.time() - first_package_sent_time
        self.__estimated_RTT = self.__sample_RTT
        self._get_new_timeout()
        print('fisrt sampleRTT inited, it\'s', self.__sample_RTT)

        # retrive data
        data = buffer_list['connecting'][remote_address].pop()
        print('retrived')

        # parse tcp object
        tcp = TCP()
        tcp.from_bytes(data)

        # check tcp object is right
        if not (tcp.SYN == 1 and tcp.ACK == 1
                and tcp.acknowledgement_number == client_isn + 1):
            print('the tcp object is not right. Connect failed')
            return

        # if it's right, update server_isn, client_isn
        server_isn = tcp.sequence_number
        client_isn += 1
        self.__next_sequence_number = client_isn
        print('client_isn sent', client_isn)
        self.__last_ack_received = tcp.acknowledgement_number

        # remove from buffer_list['connecting'], added to buffer_list['connected']
        buffer_list['connecting'].pop(remote_address)
        buffer_list['connected']['objects'][remote_address] = self

        # generate last_ack_sent and update ack_to_be_sent list, last_ack_received
        self.__last_acked_sent = server_isn + 1
        self.__ack_to_be_sent.append(self.__last_acked_sent)

        # start sending thread
        self.__sending_process = threading.Thread(target=self._sending_thread)
        self.__sending_process.start()
        print('connected')
Пример #2
0
    def _sending_thread(self):
        # build empty tcp object
        tcp = TCP()
        tcp.build(type=tcp.SEND_DATA,
                  src_port=self.__local_address[1],
                  dst_port=self.__remote_address[1])
        tcp.sequence_number = self.__next_sequence_number
        tcp.acknowledgement_number = self.__last_acked_sent
        print('built empty tcp object')

        while 1:
            time.sleep(0.2)
            # print('sending thread begin')
            # detect whether there is act_to_be_sent
            if self.__ack_to_be_sent != []:
                tcp.ACK = 1
                tcp.acknowledgement_number = self.__ack_to_be_sent.pop()
                self.__last_acked_sent = tcp.acknowledgement_number
                print(
                    'detect there is ack_to_be_sent({}), added to current tcp object, last_acked_number updated'
                    .format(tcp.acknowledgement_number))

            # check time_out
            if self.__is_time_out:
                print('detect time out')

                # get first send_but_not_acked data in tcp.data
                try:
                    tcp_bytes = self.__sent_but_not_acked[0]

                    tcp = TCP()
                    tcp.from_bytes(tcp_bytes)

                    # modify tcp.sequence_number
                    # tcp.sequence_number = waiting_ack_number - len(tcp.data)

                    # double timeout
                    self.__time_out *= 2

                    if self.__time_out <= 1:
                        self.__time_out = 1

                    # cancel SampleRTT recording for this object
                    self.__sample_RTT_to_record[tcp.sequence_number +
                                                len(tcp.data)] = None

                    # Done with here
                    self.__is_time_out = False

                    self.__timer = threading.Thread()
                    self.__timer_pid = None

                    print(self.__time_out)
                except:
                    self.__is_time_out = False

                    self.__timer = threading.Thread()
                    self.__timer_pid = None
            else:
                # print('no timeout detected')

                # calculate the spare room in sent_but_not_acked
                spare_room_in_window = self.__window_size - (
                    self.__next_sequence_number - self.__last_ack_received)

                if self.__send_buffer != b'' and spare_room_in_window != 0:  # specify squence number andNextSeqNum
                    NextSeqNum = self.__next_sequence_number

                    # prepare data
                    data = self.__send_buffer[:self.__segment_size]

                    # delete that data from send_buffer
                    self.__send_buffer = self.__send_buffer[self.
                                                            __segment_size:]

                    # update tcp object
                    tcp.data = data
                    tcp.sequence_number = NextSeqNum

            # check tcp modified
            if tcp.data != b'' or tcp.ACK == 1:
                # set sequence number
                # tcp.sequence_number = self.__next_sequence_number

                # if data included, update next_sequence_number
                if tcp.data != b'':
                    self.__next_sequence_number += len(data)

                # if the tcp contains data
                if tcp.data != b'':
                    # check the data is first sent or not

                    # add current value to sent_but_not_acked
                    if bytes(tcp) not in self.__sent_but_not_acked:
                        self.__sent_but_not_acked.append(bytes(tcp))

                    if (tcp.sequence_number + len(tcp.data)
                        ) not in self.__sample_RTT_to_record.keys():
                        # it's first sent.

                        # record send time
                        send_time = time.time()
                        self.__sample_RTT_to_record[tcp.sequence_number +
                                                    len(tcp.data)] = send_time
                        # print('----------')
                        # print('record time')
                        # print(self.__sample_RTT_to_record)
                        # print('----------')

                        # check whether there is already a tiemr
                        print('check timer', self.__timer.is_alive())
                        if not self.__timer.is_alive():
                            # there is no timer

                            # calculate a new time_out
                            self.__time_out = self._get_new_timeout()

                            # start a new timer
                            self.__timer = threading.Thread(
                                target=self.__check_time,
                                args=(time.time(), self.__time_out))
                            self.__timer.start()
                    else:
                        # it's not first sent

                        # double timeout
                        print(
                            'detect not first send message, the sequence_number is {}, the ack_number is {}, content:{}'
                            .format(tcp.sequence_number,
                                    tcp.acknowledgement_number, str(tcp)))
                        print(self.__sample_RTT_to_record)
                        self.__time_out *= 2
                        self.__timer = threading.Thread(
                            target=self.__check_time,
                            args=(time.time(), self.__time_out))
                        self.__timer.start()

                # send tcp object
                self.__ip.send(bytes(tcp))
                print(
                    'send tcp object with \tsequence number {} and \tacknowledge number {}.'
                    .format(tcp.sequence_number, tcp.acknowledgement_number))
                print('content', str(tcp))

                # build new tcp object
                tcp = TCP()
                tcp.build(type=tcp.SEND_DATA,
                          src_port=self.__local_address[1],
                          dst_port=self.__remote_address[1])
                tcp.sequence_number = self.__next_sequence_number
                tcp.acknowledgement_number = self.__last_acked_sent
Пример #3
0
    def _add_data(self, data):
        tcp = TCP()
        tcp.from_bytes(data)
        # print('retrived data from IP layer')

        # if has ack info
        if tcp.ACK == 1:
            # print("detect ACK info, it's", tcp.acknowledgement_number)
            if tcp.acknowledgement_number == self.__last_ack_received:
                # it's duplicated ack
                self.__duplicate_ack += 1
                print('detect {} duplicated ACK'.format(self.__duplicate_ack))
                if self.__duplicate_ack >= 3:
                    # fast retransmission

                    # stop timer and make timeout to be true
                    self.__timer = threading.Thread()
                    self.__timer_pid = None
                    self.__is_time_out = True
                    print(
                        'timer stoped, set timeout to be true, preparing for retransmission'
                    )
                    self.__duplicate_ack = 0
            else:
                self.__duplicate_ack = 0
                # it's not duplicated ack
                if tcp.acknowledgement_number > self.__last_ack_received:

                    print('current SendBase {}, updated to {}'.format(
                        self.__last_ack_received, tcp.acknowledgement_number))

                    # update SendBase
                    self.__last_ack_received = tcp.acknowledgement_number
                    self.__next_sequence_number = tcp.acknowledgement_number

                    # calculating a new SampleRTT
                    # print('----------')
                    # print('receive time')
                    # print(self.__sample_RTT_to_record)
                    # print('tcp info:')
                    # print('sequence_number:{}, acknowledgement_number:{}, content:{}'.format(tcp.sequence_number, tcp.acknowledgement_number, str(tcp)))
                    # print('----------')
                    try:
                        self.__sample_RTT = time.time(
                        ) - self.__sample_RTT_to_record[
                            tcp.acknowledgement_number]
                    except:
                        pass

                    # remove self.__send_but_not_acked objects according to the ack number
                    print('updating sent_but_not_acked list')
                    remove_list = []
                    for tcp_bytes in self.__sent_but_not_acked:
                        tcp_ = TCP()
                        tcp_.from_bytes(tcp_bytes)
                        if tcp_.sequence_number + len(
                                tcp_.data) <= tcp.acknowledgement_number:
                            remove_list.append(tcp_bytes)
                            print('removed waiting_ack_number:{}'.format(
                                tcp_.sequence_number + len(tcp_.data)))
                    for item in remove_list:
                        self.__sent_but_not_acked.remove(item)
                    # print('updated')

                    # check whether a timer is running
                    if self.__timer.is_alive():
                        print('detect a timer still running')

                        # check whether there are still sent_but_not_acked
                        if self.__sent_but_not_acked:
                            print('detect there is still sent_but_not_acked:')
                            print(self.__sent_but_not_acked)
                            print('restart timer')
                            self.__time_out = self._get_new_timeout()
                            # restart timer
                            self.__timer = threading.Thread(
                                target=self.__check_time,
                                args=(time.time(), self.__time_out))
                            self.__timer.start()
                        else:
                            # stop timer
                            self.__timer = threading.Thread()
                            self.__timer_pid = None
                            self.__is_time_out = False
                            self.__time_out = self._get_new_timeout()
                            print(
                                'no data in sent_but_note_acked, stopped timer'
                            )

        # if has data info:
        if tcp.data != b'':
            # check whether it's duplicate data
            if tcp.sequence_number < self.__last_acked_sent:
                print(
                    'the sequence_number({}) < last_acked_sent({}), omit it.'.
                    format(tcp.sequence_number, self.__last_acked_sent))
                # it's duplicate data
                tcp = TCP()
                tcp.build(type=tcp.SEND_ACK,
                          src_port=self.__local_address[1],
                          dst_port=self.__remote_address[1],
                          acknowledgement_number=self.__last_acked_sent)
                print('duplicate data, send ack')
            else:
                # it's not duplicate data

                # put it in self.__window_buffer and sort
                print(tcp.data, 'has added to window buffer')
                self.__window_buffer.append((tcp.sequence_number, tcp.data))
                self.__window_buffer.sort(key=lambda x: x[0])

                # check tmp_buffer in-order data, if any, put it to recv_buffer

                while self.__window_buffer[0][0] == self.__last_acked_sent:
                    # retrive from window_buffer(tmp_buffer)
                    sequence_number, data = self.__window_buffer.pop()

                    # calculate and update last_ack_sent
                    self.__last_acked_sent += len(data)

                    # put data into recv_buffer
                    self.__received_buffer += data
                    print(
                        'put data with sequence_number {} out of tmp_buffer into recv_buffer, updated last_ack_sent, waiting to be sent later'
                        .format(tcp.sequence_number))
                    if len(self.__window_buffer) == 0:
                        break

                # put last_ack_sent to ack_to_be_sent
                self.__ack_to_be_sent.append(self.__last_acked_sent)
                print('not duplicate, send ack', self.__last_acked_sent)
Пример #4
0
    def accept(self):
        """accept() -> address tuple, server_isn int

        Wait for an incoming connection.  Return a new socket
        representing the connection, and the address of the client.
        For IP sockets, the address info is a pair (hostaddr, port).
        """
        # fd, addr = self._accept()
        # If our type has the SOCK_NONBLOCK flag, we shouldn't pass it onto the
        # new socket. We do not currently allow passing SOCK_NONBLOCK to
        # accept4, so the returned socket is always blocking.
        # type = self.type & ~globals().get("SOCK_NONBLOCK", 0)
        # sock = socket(self.family, type, self.proto, fileno=fd)
        # Issue #7995: if no default timeout is set and the listening
        # socket had a (non-zero) timeout, force the new socket in blocking
        # mode to override platform-specific socket flags inheritance.
        # if getdefaulttimeout() is None and self.gettimeout():
        #     sock.setblocking(True)
        # return address, server_isn

        # if not self.__address:
        #     raise AddressNotSpecified("Did you bind address for this socket?")

        # wait until one connected
        while buffer_list['listening'][self.__local_address[1]]['queue'] == []:
            continue

        # retrive first handshake
        data, (remote_ip, remote_port) = buffer_list['listening'][
            self.__local_address[1]]['queue'].pop()
        tcp = TCP()
        tcp.from_bytes(data)
        if not (tcp.SYN == 1 and tcp.ACK == 0):
            # print("wrong tcp package received, it's not the first handshake")
            return
        client_isn = tcp.sequence_number
        print('first handshake received')

        # reformat remote_address
        address = (remote_ip, tcp.src_port)

        # generate a inital server_isn
        server_isn = random.randint(0, 2147483645)

        # build a tcp with server_isn and client_isn + 1
        tcp = TCP()
        tcp.build(type=tcp.SEND_SYNACK,
                  src_port=self.__local_address[1],
                  dst_port=address[1],
                  sequence_number=server_isn,
                  acknowledgement_number=client_isn + 1)

        # send the second handshake and register a place for handshake
        tmp_ip = IP.IP(IP.PROTOCOL_TCP, self.__local_address[0], remote_ip)
        tmp_ip.send(bytes(tcp))
        buffer_list['connecting'][address] = []
        print('second handshake sent, waiting for the third handshake')

        # record the first time of send package
        fisrt_pacakge_sent_time = time.time()

        # wait until third handshake appear
        send_send_start_time = time.time()
        flag_3 = True
        flag_6 = False
        flag_12 = False
        while buffer_list['connecting'][address] == []:
            if flag_3 and (time.time() - send_send_start_time >= 2):
                print('waiting second hand time out, wait another 6s')
                tmp_ip.send(bytes(tcp))
                send_send_start_time = time.time()
                flag_3 = False
                flag_6 = True
                send_send_start_time = time.time()
            elif flag_6 and (time.time() - send_send_start_time >= 2):
                print('waiting second hand time out, wait another 12s')
                tmp_ip.send(bytes(tcp))
                send_send_start_time = time.time()
                flag_6 = False
                flag_12 = True
                send_send_start_time = time.time()
            elif flag_12 and (time.time() - send_send_start_time >= 2):
                print('waiting second hand time out, wait another 24s')
                tmp_ip.send(bytes(tcp))
                flag_6 = False
                flag_12 = False
                send_send_start_time = time.time()
            elif (time.time() - send_send_start_time >= 4):
                print('waiting second hand time out, wait another 6s')
                print('break')
                return

            continue

        # record the time of receiving second package
        self.__sample_RTT = time.time() - fisrt_pacakge_sent_time
        self.__estimated_RTT = self.__sample_RTT
        print('first sample RTT generated, it\'s {}'.format(self.__sample_RTT))

        # retrive the third handshake
        data, address = buffer_list['connecting'][address].pop()
        tcp = TCP()
        tcp.from_bytes(data)
        print('third handshake retrived')

        # check third handshake
        if not (tcp.sequence_number == client_isn + 1
                and tcp.acknowledgement_number == server_isn + 1):
            print(
                'SYN {}, ACK{}, tcp.sequencenumber({}) ?= client_isn({}), tcp.acknowledgement_number({}) ?= server_isn({})'
                .format(tcp.SYN, tcp.ACK, tcp.sequence_number, client_isn + 1,
                        tcp.acknowledgement_number, server_isn + 1))
            print(
                "wrong tcp package received, it's not the correct third handshake"
            )
            return

        # update server_isn
        server_isn += 1

        # open a place for the newly connected socket
        buffer_list['connected'][address] = []

        # delete the original space
        buffer_list['connecting'].pop(address)

        # add data to the buffer if any

        # buffer_list['connected'][address].append(tcp.data)

        # Build a new tcpSocket
        tcpSocket = TCPsocket(self.__local_address, address, server_isn,
                              client_isn + 1, self.__sample_RTT)

        # put the conneceted object in buffer
        buffer_list['connected']['objects'][address] = tcpSocket

        # add data if any
        if tcp.data != b'':
            tcpSocket._add_data(tcp.data)
        print('done with accept, returned address and server_isn')

        return address, tcpSocket