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')
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
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)
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