def __init__(self, src_ip_ = '', dest_ip_ = '', data_ = ''): self.src_ip = src_ip_ self.dest_ip = dest_ip_ self.src_port = 0 self.dest_port = 0 self.seq_num = 0 self.ack_num = 0 # use the socket provided by network layer self.sock = IpSocket() self.pre_seq = 0 # to store the packet seq and ack number for retransmission self.pre_ack = 0 self.cwnd = 1 # the congestion window used to congestion control self.MSS = 536
def __init__(self): self.src_ip = '' self.src_port = 0 self.des_ip = '' self.des_port = 0 self.seq = 0 self.ack = 0 self.s = IpSocket() self.my_stamp = 0 self.echo_stamp = 0 self.last_time = 0 self.ack_count = 0 self.pre_ack = -1 self.pre_seq = -1
class TcpSocket: def __init__(self, src_ip_ = '', dest_ip_ = '', data_ = ''): self.src_ip = src_ip_ self.dest_ip = dest_ip_ self.src_port = 0 self.dest_port = 0 self.seq_num = 0 self.ack_num = 0 # use the socket provided by network layer self.sock = IpSocket() self.pre_seq = 0 # to store the packet seq and ack number for retransmission self.pre_ack = 0 self.cwnd = 1 # the congestion window used to congestion control self.MSS = 536 ########################################################## # connect : hostname, dest_port -> None # This method does the three way handshake and store the final # ack num and seq num for sending data and receiving data ########################################################## def connect(self, hostname, dest_port = 80): self.dest_port = dest_port src_ip_ = _get_local_host() dest_ip_ = socket.gethostbyname(hostname) self.dest_ip = dest_ip_ self.src_ip = src_ip_ self.src_port = _get_port() # here we can randomly pick one, but I'm not sure whether it is correct # new a packet and start the three way hand shake self.data = '' tcp_packet = TcpPacket(self.src_port, self.dest_port, self.src_ip, self.dest_ip, self.data) tcp_packet.syn = 1 # generate sequence number randomly self.seq_num = randint(0, 65535) # tcp_packet.set_seq_num(self.seq_num) tcp_packet.seq_num = self.seq_num count = 0 while True: if count >= 3: print "no response for 3 min, exit" sys.exit(0) self._send(tcp_packet.wrap()) tcp_packet = self._recv_until_timeout() # raw_packet = self.sock.recv() if tcp_packet == '' and count < 3: count += 1 print count continue if tcp_packet.rst == 1: print "error due to reset" sys.exit(0) else: # receive the ack msg from server successfully if tcp_packet.syn == 1 and tcp_packet.ack == 1 and tcp_packet.ack_num == self.seq_num + 1: self.seq_num = tcp_packet.ack_num self.ack_num = tcp_packet.seq_num break else: count += 1 print count continue tcp_packet = TcpPacket(self.src_port, self.dest_port, self.src_ip, self.dest_ip, self.data) tcp_packet.ack = 1 tcp_packet.seq_num = self.seq_num tcp_packet.ack_num = self.ack_num + 1 self.ack_num = self.ack_num + 1 self._send(tcp_packet.wrap()) # til now, three way shakes finished ########################################################## # send : data -> None # This method is used to send data to the server using the # the seq number and ack number stored at the end of the # three handshake or other part. This method implements # congestion control. Also, it will wait for the ack for the # data sent. After for 1 minute, it will resend the data. And # if for 3 mintues no response, the program will exit ########################################################## def send(self, data): # build a new tcp packet and send it to the dest ip, then wait for the ack. # If the wait time exceeds the timeout, retransmit this packet # slow start self.cwnd = self.MSS while len(data) > 0: send_data = data[:self.cwnd] data = data[self.cwnd:] tcp_packet = TcpPacket(self.src_port, self.dest_port, self.src_ip, self.dest_ip, data) tcp_packet.seq_num = self.seq_num tcp_packet.ack_num = self.ack_num tcp_packet.ack = 1 tcp_packet.psh = 1 tcp_packet.data = send_data # send the packet out using the send method provided by network layer self._send(tcp_packet.wrap()) # receive process while True: tcp_packet_receive = self._recv_until_timeout() if tcp_packet_receive == '': print "received ack errors" tcp_packet_retrans = TcpPacket(self.src_port, self.dest_port, self.src_ip, self.dest_ip, data) tcp_packet_retrans.seq_num = self.seq_num tcp_packet_retrans.ack_num = self.ack_num tcp_packet_retrans.ack = 1 tcp_packet_retrans.psh = 1 # can't receive the ack, decrease the cwnd if self.cwnd > 1: self.cwnd /= 2 else: self.cwnd = self.MSS tcp_packet_retrans.data = send_data try: self._send(tcp_packet_retrans.wrap()) except: continue # tcp_packet.reset() else: # filter the packet, the packet we want should be a ack packet # and the ack num should be the seq_num we send + data size(the next seq_num the # receiver wants) # print tcp_packet_receive.ack_num, self.seq_num + min(self.cwnd, len(send_data)) if tcp_packet_receive.rst == 1: print "error due to reset" sys.exit(0) if tcp_packet_receive.ack == 1 and tcp_packet_receive.ack_num == (self.seq_num + min(self.cwnd, len(send_data))): # succeeds receiving ack, increase the cwnd self.cwnd *= 2 self.pre_ack = self.ack_num self.pre_seq = self.seq_num self.seq_num = tcp_packet_receive.ack_num self.ack_num = tcp_packet_receive.seq_num # self.data = data break else: continue ########################################################## # recv_all : None -> data # This method is used to receive the data sent from the server # It will check the seq number of the data received and tell # whether it is the packet previously acked. If not, this metod # will request for the retransmission. The method will continue # receiving the data until the server sends the fin for tearing # down the connection. ########################################################## def recv_all(self): result_data = [] # ack_count = 0 while True: tcp_packet = self._recv_until_timeout() # timeout, nothing get, exit the program if tcp_packet == '': print "received errors" sys.exit(0) # if we receive a reset packet, the connection is done, exit the program if tcp_packet.rst == 1: print "received errors" sys.exit(0) else: # check the seq number, if it is the packet we want, ack new packet # otherwise request for retransmission if tcp_packet.seq_num == self.pre_ack: # If the server sends the finish packet, ack this finish packet # and ends the receiving process if tcp_packet.fin == 1 : self.ack_num = tcp_packet.seq_num + len(tcp_packet.data) + 1 self.seq_num = tcp_packet.ack_num tcp_packet_for_ack_fin = TcpPacket(self.src_port, self.dest_port, self.src_ip, self.dest_ip, '') tcp_packet_for_ack_fin.ack = 1 tcp_packet_for_ack_fin.ack_num = self.ack_num tcp_packet_for_ack_fin.seq_num = self.seq_num self._send(tcp_packet_for_ack_fin.wrap()) self.pre_ack = self.ack_num self.pre_seq = self.seq_num break # if the packet is not a finished pacekt, continue reveiving the data else: result_data.append(tcp_packet.data) self.seq_num = tcp_packet.ack_num self.ack_num = tcp_packet.seq_num + len(tcp_packet.data) tcp_packet_for_ack_next = TcpPacket(self.src_port, self.dest_port, self.src_ip, self.dest_ip, '') tcp_packet_for_ack_next.ack = 1 tcp_packet_for_ack_next.seq_num = self.seq_num tcp_packet_for_ack_next.ack_num = self.ack_num self._send(tcp_packet_for_ack_next.wrap()) self.pre_seq = self.seq_num self.pre_ack = self.ack_num # If the received packet is wrong, do retransmission process elif tcp_packet.seq_num != self.pre_ack: tcp_packet_ack_loss_packet = TcpPacket(self.src_port, self.dest_port, self.src_ip, self.dest_ip, '') tcp_packet_ack_loss_packet.ack_num = self.pre_ack tcp_packet_ack_loss_packet.seq_num = self.pre_seq tcp_packet_ack_loss_packet.ack = 1 self._send(tcp_packet_ack_loss_packet.wrap()) return ''.join(result_data) ########################################################## # close : None -> None # This method is used to finish a connection. First, it will # send the fin+ack packet to the server. If no response, exit # the method, if the server sends the fin+ack, it will send # the ack as well. ########################################################## def close(self): # send the fin+ack packet to the server tcp_packet_for_fin = TcpPacket(self.src_port, self.dest_port, self.src_ip, self.dest_ip, '') tcp_packet_for_fin.fin = 1 tcp_packet_for_fin.ack = 1 tcp_packet_for_fin.ack_num = self.ack_num tcp_packet_for_fin.seq_num = self.seq_num self._send(tcp_packet_for_fin.wrap()) # wait for the response tcp_packet = self._recv_until_timeout() # timeout and no response, exit if tcp_packet == '': print 'can\'t receive ack, client finishes itself' sys.exit(0) # get a reset packet, exit if tcp_packet.rst == 1: print "error due to reset" sys.exit(0) else: # received a fin+ack packet, send the ack packet to server and ends the close method if self.ack_num == tcp_packet.seq_num and self.seq_num + 1== tcp_packet.ack_num and tcp_packet.fin == 1 and tcp_packet.ack == 1: print "correct" self.ack_num = tcp_packet.seq_num + 1 self.seq_num = tcp_packet.ack_num tcp_packet = TcpPacket(self.src_port, self.dest_port, self.src_ip, self.dest_ip, '') tcp_packet.ack_num = self.ack_num tcp_packet.seq_num = self.seq_num tcp_packet.fin = 1 self._send(tcp_packet.wrap()) return # received a ack packet, end the close method elif self.ack_num == tcp_packet.seq_num and self.seq_num + 1== tcp_packet.ack_num and tcp_packet.ack == 1 and tcp_packet.fin == 0: # print "finish" return else: print "some error happens" sys.exit(0) ###################################################### # _send : encoded tcp_packet -> None # This method is a private method for sending data use the # socket provided by the network layer. It will contiune # trying to send the data until it succeeds or 10 times ###################################################### def _send(self, tcp_packet): count = 0 while True: try: self.sock.send(self.src_ip, self.dest_ip, tcp_packet) break except: if count > 10: print "some errors happens, please check you device and try again" sys.exit(0) count += 1 continue ###################################################### # _recv_until_timeout : None -> tcp packet object # This method is a private method for receiving the data # it will contiune trying to receive the right tcp packet # until it succeeds or time out ####################################################### def _recv_until_timeout(self): start = time.time() tcp_packet = TcpPacket() while time.time() - start < MAX_TIMEOUT: # try the recv() method provided network layer try: raw_packet = self.sock.recv(socket.IPPROTO_TCP) except: continue # do the checksum tcp_packet.src_ip = self.dest_ip tcp_packet.dest_ip = self.src_ip try: tcp_packet.unwrap(raw_packet) except ValueError: continue # if the packet port is correct, return the tcp packet object- if tcp_packet.src_port == self.dest_port and tcp_packet.dest_port == self.src_port: return tcp_packet else: continue return ''
class TcpSocket: def __init__(self): self.src_ip = '' self.src_port = 0 self.des_ip = '' self.des_port = 0 self.seq = 0 self.ack = 0 self.s = IpSocket() self.my_stamp = 0 self.echo_stamp = 0 self.last_time = 0 self.ack_count = 0 self.pre_ack = -1 self.pre_seq = -1 def connect(self,des_addr, des_port_=80): self.des_ip = socket.gethostbyname(des_addr) self.des_port = des_port_ self.src_ip = self.get_self_ip() self.src_port = self.get_free_port() #self.s.src = self.src_ip #self.s.des = self.des_ip # three way hand shake begins: self.seq = randint(0, 65535) packet = self.new_out_packet() packet.flag_syn = 1 # send syn self._send(self.src_ip, self.des_ip, packet) # receive syn+ack packet.reset() packet = self._recv() if packet == '': print 'Socket time out(0)' sys.exit(0) if packet.ack_no == (self.seq + 1) and packet.flag_syn == 1 and packet.flag_ack == 1: self.ack = packet.seq_no + 1 self.seq = packet.ack_no else: print 'Malformed SYN+ACK packet(1)' sys.exit(0) # send ack packet = self.new_out_packet() packet.flag_ack = 1 #packet.data = 'GET /home/cbw/networks.html HTTP/1.1\n\n' self._send(self.src_ip, self.des_ip, packet) def send(self, _data): 'Send the packet' packet = self.new_out_packet() packet.flag_ack = 1 packet.flag_psh = 1 packet.data = _data self._send(self.src_ip, self.des_ip, packet) 'Get ack of the sent packet' packet.reset() packet = self._recv() if packet == '': print 'Socket timeout(2)' sys.exit(0) if packet.ack_no == (self.seq + len(_data)): self.ack = packet.seq_no + len(packet.data) self.seq = packet.ack_no else: print 'Malformed ACK packet(3)' sys.exit(0) def recv(self): tcp_data = '' #st_time = time.time() packet = IpPacket() while 1: #(time.time() - st_time) < 0.5: if self.ack_count > 1: 'send ack packet' packet = self.new_out_packet() 'set ack to previous packet' packet.ack_no = self.pre_ack packet.seq_np = self.pre_seq packet.flag_ack = 1 self._send(self.src_ip, self.des_ip, packet) 'after send ack, decrease ack_count by 1' self.ack_count -= 1 'recv packet' packet.reset() packet = self._recv() if packet == '': break 'first set previous ack# to current ack' if self.ack_count > 0: self.pre_ack = self.ack self.pre_seq = self.seq self.ack = packet.seq_no + len(packet.data) self.seq = packet.ack_no tcp_data += packet.data 'add 1 to ack_count, for acknowledge' self.ack_count += 1 #packet = self.new_out_packet() #packet.flag_ack = 1 #self._send(self.src_ip, self.des_ip, packet) #''' #''' return tcp_data def close(self): 'send fin+ack' packet = self.new_out_packet() packet.flag_fin = 1 #packet.data = 'aaaaa' if self.ack_count > 0: packet.flag_ack = 1 packet.flag_psh = 1 self._send(self.src_ip, self.des_ip, packet) 'recv fin+ack' packet.reset() packet = self._recv() if packet == '': return 0 self.ack = packet.seq_no + 1 self.seq = packet.ack_no 'send ack' packet = self.new_out_packet() packet.flag_ack = 1 self._send(self.src_ip, self.des_ip, packet) def new_out_packet(self): packet = TcpPacket() packet.source = self.src_port packet.destination = self.des_port packet.src_ip = self.src_ip packet.des_ip = self.des_ip packet.seq_no = self.seq packet.ack_no = self.ack return packet def get_self_ip(self): return get_address('eth0', 'ip') ''' s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) s.connect(('www.google.com', 80)) ip = s.getsockname()[0] s.close() return ip ''' def get_free_port(self): s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.bind(('', 0)) s.listen(1) port = s.getsockname()[1] s.close() return port def _send(self, src_ip_, des_ip_, packet_): self.s.send(src_ip_, des_ip_, packet_.assemble()) #print 'send:' #packet_.print_packet() def _recv(self): packet = TcpPacket() st_time = time.time() while (time.time() - st_time) < TIME_OUT: packet.reset() try: pkt = self.s.recv() except: continue 'packet received' packet.src_ip = self.des_ip packet.des_ip = self.src_ip packet.disassemble(pkt) #print 'recv:' #packet.print_packet() if packet.source == self.des_port and packet.destination == self.src_port: return packet return ''