def terminate(self): while self.client_state != States.CLOSED: if self.client_state == States.ESTABLISHED: terminate_header = utils.Header(self.next_seq_num, self.last_received_seq_num + 1, syn=0, ack=1, fin=1) self.next_seq_num += 1 send_udp(terminate_header.bits()) self.update_state(States.FIN_WAIT_1) elif self.client_state == States.FIN_WAIT_1: recv_data, addr = sock.recvfrom(1024) fin_ack_header = utils.bits_to_header(recv_data) self.last_received_seq_num = fin_ack_header.seq_num if fin_ack_header.ack == 1: self.update_state(States.FIN_WAIT_2) elif self.client_state == States.FIN_WAIT_2: recv_data, addr = sock.recvfrom(1024) fin_fin_header = utils.bits_to_header(recv_data) self.last_received_seq_num = fin_fin_header.seq_num if fin_fin_header.fin == 1: terminate_ack_header = utils.Header( self.next_seq_num, self.last_received_seq_num + 1, syn=0, ack=1, fin=0) self.next_seq_num += 1 send_udp(terminate_ack_header.bits()) self.update_state(States.CLOSED) else: pass
def terminate(self): if self.client_state == States.ESTABLISHED: # send FIN message fin_header = utils.Header(self.my_next_seq, 0, syn=0, ack=0, fin=1) send_udp(fin_header.bits()) # update my seq self.my_next_seq += 1 # update state self.update_state(States.FIN_WAIT_1) else: raise RuntimeError("invalid states for termination") # wait for ack if self.client_state == States.FIN_WAIT_1: recv_data, addr = sock.recvfrom(1024) header = utils.bits_to_header(recv_data) if header.ack == 1 and header.ack_num == self.my_next_seq: # update server seq self.server_next_seq = header.seq_num + 1 # update client state self.update_state(States.FIN_WAIT_2) else: raise RuntimeError("invalid server ack") else: raise RuntimeError("invalid states for termination") # wait for server FIN and send back a ACK if self.client_state == States.FIN_WAIT_2: recv_data, addr = sock.recvfrom(1024) header = utils.bits_to_header(recv_data) if header.fin == 1: # update server seq self.server_next_seq = header.seq_num + 1 # send back a ack ack_header = utils.Header(self.my_next_seq, self.server_next_seq, syn=0, ack=1, fin=0) send_udp(ack_header.bits()) # update client seq self.my_next_seq += 1 # update client state self.update_state(States.TIME_WAIT) else: raise RuntimeError("invalid server fin") else: raise RuntimeError("invalid states for termination") # wait for 2 maximum segment life time then close the client if self.client_state == States.TIME_WAIT: time.sleep(2 * MSL) self.my_next_seq = -1 self.server_next_seq = -1 self.update_state(States.CLOSED) else: raise RuntimeError("invalid states for termination")
def handshake(self): while self.client_state != States.ESTABLISHED: if self.client_state == States.CLOSED: seq_num = utils.rand_int() self.next_seq_num = seq_num + 1 syn_header = utils.Header(seq_num, 0, syn=1, ack=0, fin=0) # for this case we send only header; # if you need to send data you will need to append it send_udp(syn_header.bits()) self.update_state(States.SYN_SENT) elif self.client_state == States.SYN_SENT: recv_data, addr = sock.recvfrom(1024) syn_ack_header = utils.bits_to_header(recv_data) self.last_received_seq_num = syn_ack_header.seq_num if syn_ack_header.syn == 1 and syn_ack_header.ack == 1: ack_header = utils.Header(self.next_seq_num, self.last_received_seq_num + 1, syn=0, ack=1, fin=0) self.next_seq_num += 1 send_udp(ack_header.bits()) self.update_state(States.ESTABLISHED) else: pass
def receive_acks_sub_process_stop_and_wait(self, lst_rec_ack_shared): while True: recv_data, addr = sock.recvfrom(1024) header = utils.bits_to_header(recv_data) if header.ack == 1 and header.ack_num == lst_rec_ack_shared.value + 1: lst_rec_ack_shared.value = header.ack_num break
def recv_msg(): try: data, addr = sock.recvfrom(1024) header = utils.bits_to_header(data) body = utils.get_body_from_data(data) return (header, body, addr) except socket.timeout: return (None, None, None)
def receive_acks_sub_process_go_back_n(self, lst_rec_ack_shared): lra = lst_rec_ack_shared.value # a list marks which message is acked acked = [0] * (SENDER_WINDOW_SIZE + 1) # a pointer points to current window side cur = 0 while True: recv_data, addr = sock.recvfrom(1024) header = utils.bits_to_header(recv_data) if header.ack == 1 and header.ack_num > lra and header.ack_num <= lra + SENDER_WINDOW_SIZE: # mark this ack acked[header.ack_num - lra] = 1 # move the pointer if possible while cur < SENDER_WINDOW_SIZE and acked[cur + 1] == 1: cur += 1 # reset lst_rec_ack lst_rec_ack_shared.value += 1 if cur == SENDER_WINDOW_SIZE: # now we received all acks break
def send_reliable_message(self, message): count= 0 MSS = 2 # split the message into chunks msg = message.split() #seq number seq_num = utils.rand_int() # Create the header we attach to our message msg_header = utils.Header(seq_num, 0, syn = 0, ack = 1, fin = 0) # Send initial chunk chunk = msg[count:count + 3] chunk = ','.join(chunk[0:2]) send_udp(msg_header.bits() + chunk.replace(",", " ").encode()) count += 2 while count <= 7: #handle seq / ack recv_data, addr = sock.recvfrom(1024) #receive the data sent from the server msg_header = utils.bits_to_header(recv_data) #convert received data to header format firstseq = msg_header.seq_num # first msg seq number if msg_header.seq_num == firstseq or msg_header.seq_num == subseq: #check current seq numb from previous, make sure increments by 1 chunk = msg[MSS:MSS + 3] # chunk = ','.join(chunk[0:2]) send_udp(msg_header.bits() + chunk.replace(",", " ").encode()) count += 2 MSS += 2 subseq = msg_header.seq_num + 1 else: #if seq are not incrementing correctly then send previous chunk again print(msg_header.seq_num) #just printing out the seq number MSS -= 2 chunk = msg[MSS:MSS - 3] # chunk = ','.join(chunk[0:2]) send_udp(msg_header.bits() + chunk.replace(",", " ").encode()) #handle stop and wait pass
def send_reliable_message(self, message): # send messages # we loop/wait until we receive all ack. self.receive_acks() count = 0 msg = message.split() while count <= 6: chunk = msg[count:count + 3] chunk = ','.join(chunk[0:2]) chunk.replace(",", " ") print(chunk.replace(",", " ")) try: recv_data, addr = sock.recvfrom(1024) ack_header = utils.bits_to_header(recv_data) except socket.timeout: self.next_seq_num -= MSS continue if ack_header.ack_num != self.next_seq_num: self.next_seq_num -= MSS continue self.last_received_seq_num = ack_header.seq_num count += 2
def handshake(self): if self.client_state == States.CLOSED: seq_num = utils.rand_int() syn_header = utils.Header(seq_num, 0, syn=1, ack=0, fin=0) # for this case we send only header; # if you need to send data you will need to append it send_udp(syn_header.bits()) # update client seq number self.my_next_seq = seq_num + 1 self.update_state(States.SYN_SENT) else: raise RuntimeError("invalid states for start a handshake.") # we wait for server to send back a SYN-ACK message if self.client_state == States.SYN_SENT: recv_data, addr = sock.recvfrom(1024) header = utils.bits_to_header(recv_data) # server syn header should have both syn and ack fields # and the ack_num should be client next sequence number if header.ack == 1 and header.syn == 1 and header.ack_num == self.my_next_seq: self.server_next_seq = header.seq_num + 1 self.last_received_ack = header.ack_num + 1 else: raise RuntimeError( "invalid server SYN-reply, handshake failed.") # we send back ACK message ack_header = utils.Header(self.my_next_seq, self.server_next_seq, syn=0, ack=1, fin=0) send_udp(ack_header.bits()) # update my seq self.my_next_seq += 1 # update state -> connection established on the client's perspective self.update_state(States.ESTABLISHED) else: raise RuntimeError("invalid states for waiting server SYN-reply.")
def chan_server(): global sock_client, sock_server, wait_send, addr_client, round while True: # need to wait until initial client message sent # to server, otherwise socket from server # is not valid (so sock_server.recvfrom will error) while wait_send == 0: pass print('waiting on server response') data_server, addr_server = sock_server.recvfrom(1024) header = utils.bits_to_header(data_server) if round >= 2 and (header.ack == 1 and header.syn == 0 and header.fin == 0) and random.randint(1, 10) <= 3: print("DROPPING ACK FROM SERVER") continue print(addr_server) print('forwarding to client') time.sleep(sleep_v) sock_client.sendto(data_server, (UDP_IP, addr_client[1])) time.sleep(sleep_v) round = round + 1
def chan_client(): global sock_client, sock_server, wait_send, addr_client while True: print('waiting on client') data_client, addr_client = sock_client.recvfrom(1024) header = utils.bits_to_header(data_client) print(addr_client) print(addr_client[0]) # ip print(addr_client[1]) # port time.sleep(sleep_v) # drop messages randomly, after connection established #if round >= 2 and random.randint(1,10) <= 3: if round >= 2 and (header.ack == 0 and header.syn == 0 and header.fin == 0) and random.randint(1, 10) <= 3: print("DROPPING MESSAGE FROM CLIENT") continue print('forwarding to server') sock_server.sendto(data_client, (UDP_IP, UDP_PORT_SERVER)) time.sleep(sleep_v) wait_send = 1
def recv_msg(): data, addr = sock.recvfrom(1024) header = utils.bits_to_header(data) body = utils.get_body_from_data(data) return (header, body, addr)
def receive_acks_sub_process(self, lst_rec_ack_shared): while True: recv_data, addr = sock.recvfrom(1024) header = utils.bits_to_header(recv_data) if header.ack_num > lst_rec_ack_shared.value: lst_rec_ack_shared.value = header.ack_num