def _connect(self): debug_log("start three-way handshake") syn_segment = self.segment_factory.create_syn() self.seq_num = syn_segment.seq_num debug_log("send syn to server") # send syn to the server, resend if timeout self._send_segment(syn_segment) try: ack_syn_segment = self._receive_ack(1, 0) except TimeoutError: self._send_segment(syn_segment) try: ack_syn_segment = self._receive_ack(1, 0) except TimeoutError: # exit the program if still timeout sys.exit(-1) error_log("failed to create a TCP connection") debug_log("receive ack syn from server") # add 1 to the sequence number self.seq_num += 1 # set the ack number self.ack_num = ack_syn_segment.seq_num + 1 ack_segment = self.segment_factory.create_ack(self.seq_num, self.ack_num) self._send_segment(ack_segment) debug_log("send ack to server") debug_log("complete three-way handshake")
def _receive_datagram(self): while True: ip_datagram = dissemble(self.eth_socket.receive()) if ip_datagram is not None: debug_log("receive datagram from " + ip_datagram.src_ip + " to " + ip_datagram.dest_ip) if ip_datagram.src_ip == self.dest_ip and ip_datagram.dest_ip == self.src_ip: return ip_datagram
def _send_data_in_queue(self): # window size should be min(cwnd, awnd) wnd_size = min(self.cwnd * MSS, self.awnd) while wnd_size > 0 and len(self.sender_queue) > 0: data_segment = self.sender_queue.popleft() if len(data_segment.data) < wnd_size: debug_log("send request data to the server, sequence number: " + str(self.seq_num)) self._send_segment(data_segment) expected_ack_num = self.seq_num + len(data_segment.data) self.unacked_segments[expected_ack_num] = data_segment wnd_size -= len(data_segment.data) else: self.sender_queue.appendleft(data_segment) break
def _get_remote_mac(self, src_ip, src_mac, gate_ip): spa = src_ip sha = src_mac tpa = gate_ip tha = self.dest_mac sent_arp_pac = arp_packet.ARPPacket(sha, spa, tha, tpa) sent_arp_data = arp_packet.assemble(sent_arp_pac) debug_log("send arp request") self.send(sent_arp_data, type_num=HTYPE_ARP) recv_arp_data = self.receive(type_num=HTYPE_ARP) debug_log("receive arp response") recv_arp_pac = arp_packet.dissemble(recv_arp_data) return recv_arp_pac.sha
def _partition_data(self, data): seg_seq_num = self.seq_num total_len = len(data) remain_len = total_len start_index = 0 while remain_len > MSS: partitioned_data = data[start_index: start_index + MSS] debug_log("partition data: " + partitioned_data + ", seq_num: " + str(seg_seq_num)) partitioned_data_seg = self.segment_factory.create_psh_ack(seg_seq_num, self.ack_num, partitioned_data) seg_seq_num += MSS start_index += MSS remain_len -= MSS # add the segment into the sender queue self.sender_queue.append(partitioned_data_seg) # add the last segment last_data = data[start_index: total_len] last_data_seg = self.segment_factory.create_psh_ack(seg_seq_num, self.ack_num, last_data) self.sender_queue.append(last_data_seg)
def _receive_data_and_send_ack(self): init_data_index = self.ack_num unordered_data = dict() while True: segment = self._receive_segment() data = segment.data segment_index = segment.seq_num - init_data_index expected_index = self.ack_num - init_data_index # if the server sends fin and all data before has been received, break the auto ack mode if segment.fin == 1 and segment_index == expected_index: if len(data) != 0: self._handle_ordered_data(data) # ack to fin self.ack_num += 1 fin_ack_segment = self.segment_factory.create_fin_ack( self.seq_num, self.ack_num) self._send_segment(fin_ack_segment) debug_log("ack to fin") if self._receive_segment().ack == 1: debug_log("successfully close the connection") self.connection_closed = True break # duplicate segment, drop it and ack (the ack number should be correct) if segment_index < expected_index: debug_log("get duplicate segment") ack_segment = self.segment_factory.create_ack(self.seq_num, segment_index + init_data_index) self._send_segment(ack_segment) continue # new ordered segment (handle it and all cached unordered data) elif segment_index == expected_index: debug_log("get ordered segment") self._handle_ordered_data(data) self._handle_unordered_data(unordered_data) # unordered data, cache it else: debug_log("get unordered segment") unordered_data[segment_index] = segment.data ack_segment = self.segment_factory.create_ack(self.seq_num, self.ack_num) self._send_segment(ack_segment)
def close(self): if not self.connection_closed: fin_segment = self.segment_factory.create_fin(self.seq_num, self.ack_num) # send fin to the server, resend if timeout self._send_segment(fin_segment) try: ack_fin_segment = self._receive_ack(0, 1) except TimeoutError: self._send_segment(fin_segment) try: ack_fin_segment = self._receive_ack(0, 1) except TimeoutError: # return False if still timeout return False debug_log("receive ack fin from server") self.seq_num += 1 self.ack_num += 1 ack_segment = self.segment_factory.create_ack(self.seq_num, self.ack_num) self._send_segment(ack_segment) debug_log("send ack to server") debug_log("complete connection teardown") return True