def rcv_pkg(self, ack_pkg:TCPPackage): if self.finished: return ack = ack_pkg.ack_number self._set_ertt_dev_ertt(ack) self._set_rws(ack_pkg.window_size) base_seq_num = self.base + self.base_seq_number if base_seq_num < ack: self.base = ack - self.base_seq_number self._handle_new_ack() if self.base >= self.next_to_send: self.timer.stop() elif self.rws: self._handle_dupl_ack() times = self.fast_retr.pop(ack,1) if times == 3: # Fast Retransmition log.info(f"FAST RTM ACK:{ack} {self.__conn._info()}") if not self.finished: self._build_and_send_pkg(ack - self.base_seq_number) else: self.fast_retr[ack] = times + 1
def _reset_variables(self): log.info(f"SENDER STOP {self.__conn._info()}") self.finished = True self.data = None self.pkg_sending = None self.fast_retr = dict() self.ack_sent = dict()
def __send(self): while self.__running and self.base < len(self.data): last_to_send = min(len(self.data), self.base + min(self.cws, self.rws)) while self.next_to_send < last_to_send: pkg_sent = self._build_and_send_pkg(self.next_to_send) self.next_to_send += len(pkg_sent.data) if not self.timer.running(): self.timer.start() while self.timer.running() and not self.timer.timeout(): time.sleep(0.05) if self.timer.timeout(): if self.timer._duration > self.MAX_WAITING_TIME: self.sender_error.append("Wait time reached max value") break self.next_to_send = self.base self.timer.stop() if self.rws: # Space in recv buffer self._handle_timeout() self.timer.set_duration(self.timer._duration * 2) # Timeout double the interval log.info(f"TIMEOUT {self.__conn._info()} {self.timer._duration}") else: log.info(f"RCV BUF FULL {self.__conn._info()}") self._reset_variables() self._next_scheduled()
def my_send_data(): conn = dial(address) data = b"123456789a123456789b123456789c123456789d123456789e123456789f123456789g" size = 10 while data: pkg, data = data[:size], data[size:] len_send = send(conn, pkg) log.info(f"Sent {pkg[:len_send]}") data = pkg[len_send:] + data close(conn)
def _send_flow_update_ack(self, current_ack:int): log.info(f"FLOW CTRL ON {self._info()}") while not self.window_size and self.__flow_ack_active: # Wait for space in buffer time.sleep(0.5) while self.ack_number == current_ack and self.__flow_ack_active: # Wait for sender to restart send data self._send_ack() # Send ack to notify sender the available space time.sleep(self.FLOW_WAITING) self.__flow_ack_active = False log.info(f"FLOW CTRL OFF {self._info()}")
def start(self): """ Start the TCP functionality. Must be called before any other method """ if not self.__running: self.__running = True self.recv_thread = Thread(target=self.demultiplex, name='TCP', daemon=True) self.recv_thread.start() log.info("TCP Started")
def end(self): """ Release all TCP resources and close all connections """ if self.__running: self.close_all() self.__running = False self.recv_thread.join(2) self.recv_sock.close() log.info("TCP Closed")
def my_recv_data(): server = listen(address) conn = accept(server) close(server) data = b'' rcv_data = True while rcv_data: rcv_data = recv(conn, 1) log.info(f"Received {rcv_data}") data += rcv_data log.info(f"Final data {data}") close(conn)
def _send_no_conn_reply(self, package:TCPPackage): """ Send a rst package to client """ with ut.get_raw_socket() as s: # Change package information # Set rst flag to notify that no conn exist with the package address flags = ut.PacketFlags(False, True, False, False, False, False, False, False) info = ut.PacketInfo(package.dest_host, package.source_host, package.dest_port, package.source_port, package.ack_number, package.seq_number,0, flags, 0, package.window_size) package = TCPPackage(b"", info, True) s.sendto(package.to_bytes(),(package.dest_host, package.dest_port)) log.info(f"RST Package sent {package._endpoint_info()}")
def _set_ertt_dev_ertt(self, ack:int): value = self.ack_sent.get(ack,None) if not value: return sent_time, sent_times = value if sent_times == 1: now = time.time() rtt = now - sent_time if self.ertt: self.ertt = (1-self.RTT_WEIGHT) * self.ertt + self.RTT_WEIGHT * rtt self.dev_ertt = (1 - self.DEV_ERRT_WEIGHT) * self.dev_ertt + self.DEV_ERRT_WEIGHT * abs(self.ertt - rtt) else: self.ertt = now - sent_time self.dev_ertt = 0 self.timer.set_duration(self.timeout_duration) log.info(f"TIMER RST {self.timeout_duration} {self.__conn._info()}") self.ack_sent[ack] = [time,2] # In case of rereceive the ack the time is invalid
def demultiplex(self): """ Redirects incoming packages to corresponding connection """ while self.__running: data = self.recv_sock.recv(2048) package = TCPPackage(data) package = self._can_queue_data(package): if package: log.info(f"TCP recv package: {package._info()}") conn = self.conn_dict.get(package.dest_host, package.dest_port, package.source_host, package.source_port) server_conn = self.conn_dict.get_server(package.dest_host,package.dest_port) if conn: conn.handle_pkg(package) elif server_conn and package.syn_flag: conn = server_conn.server_handle_pkg(package) if conn: TCP.add_connection(conn)
def __send_pkg(self, pkg:TCPPackage): while self.__running and self.base < 1: self.__send_pkg_raw(pkg) if not self.timer.running(): self.timer.start() while self.timer.running() and not self.timer.timeout(): time.sleep(0.05) if self.timer.timeout(): if self.timer._duration > self.MAX_WAITING_TIME: self.sender_error.append("Wait time reached max value") break self.timer.stop() self.timer.set_duration(self.timer._duration * 2) # Timeout double the interval log.info(f"TIMEOUT {pkg._endpoint_info()} {self.timer._duration}") self._reset_variables() self._next_scheduled()
def client_test(): conn = dial(address) log.info("Client Done") data = b'123456789a123456789b123456789c123456789d123456789e123456789f123456789g123456789h' data_send_len = send(conn, data) log.info(f"Client Sended: {data_send_len} of {len(data)}") close(conn) log.info("Client Closed")
def server_test(): server = listen(address) client_con = accept(server) log.info("Server Done") data_recv = None data = b"" while True: try: data = recv(client_con, 2048) except Exception: break log.info(f"Server Recv {data}") if data_recv == None: data_recv = b"" data_recv += data log.info(f"Server Received: {data_recv} length:{len(data_recv)}") close(server) close(client_con) log.info("Client Server Closed")
def delete_server(self, host:str, port:int): log.info(f"Server Connection deleted: {host}:{port}") self.server_conn_dict.pop((host, port),None)
def state(self, value:str): log.info(f"{self.state}->{value} CWS:{self.cws} SST:{self.ssthr} DACK:{self.dupl_ack} {self.__conn._info()}") self.__state = value
def state(self, value:str): log.info(f"CHNG CON STATE {self.state}->{value} {self._info()}") if value == Conn.CLOSED and self.state != Conn.CLOSED: self.__close_pkg_sent = False # Flag for last conn empty pkg self.__state = value
def delete(self, source_host:str, source_port:int, dest_host:str, dest_port:int): log.info(f"Connection deleted: {source_host}:{source_port} -> {dest_host}:{dest_port}") self.conn_dict.pop((source_host, source_port, dest_host, dest_port),None)
def add_server(self, conn: Conn): host, port = conn.local_host, conn.local_port log.info(f"Server Connection added: {host}:{port}") self.server_conn_dict[host,port] = conn
def __send_pkg_raw(self, pkg:TCPPackage): log.info(f"SENT LEN:{len(pkg.data)} {pkg._info()}") self._set_expecting_ack(pkg.expected_ack) self.sock.sendto(pkg.to_bytes(), (pkg.dest_host, pkg.dest_port))
def add(self, conn: Conn): source_host, source_port, dest_host, dest_port = conn.local_host, conn.local_port, conn.dest_host, conn.dest_port log.info(f"Connection added: {source_host}:{source_port} -> {dest_host}:{dest_port}") self.conn_dict[source_host,source_port,dest_host,dest_port] = conn