def send_packet(self, data, dst_l2_addr=None, callback=None, callback_args=tuple()): """Processing a packet from the SCHC layer to southbound""" dprint("L2: sending a packet", data.hex()) self.system.log("L2", "send packet to devaddr={} packet={}".format( dst_l2_addr, data.hex())) body = json.dumps({"hexSCHCData": data.hex(), "devL2Addr": dst_l2_addr}) """ self.system.scheduler.loop.run_in_executor( None, self._post_data, self.config["downlink_url"], body, self.config["ssl_verify"]) """ current_clock = self.system.scheduler.get_clock() diff = current_clock - self.last_clock if diff > self.config["tx_interval"]: delay = self.config["tx_interval"] else: delay = self.config["tx_interval"] - diff self.last_clock = current_clock self.system.scheduler.add_event(delay, self._post_data, (self.config["downlink_url"], body, self.config["ssl_verify"])) status = 0 # if callback is not None: # XXX status should be taken from the run_in_executor(). args = callback_args + (status,) callback(*args)
def schc_recv(self, sender_l2_address, raw_packet): #self._log("recv-from-L2 {} {}".format(sender_l2_addr, raw_packet)) frag_rule = self.rule_manager.FindFragmentationRule() packet_bbuf = BitBuffer(raw_packet) dtrace('>', binascii.hexlify(packet_bbuf.get_content()), ' ') dtrace ('\t\t\t-----------{:3}--------->|'.format(len(packet_bbuf._content))) dtag_length = frag_rule[T_FRAG][T_FRAG_PROF][T_FRAG_DTAG] if dtag_length > 0: dtag = packet_bbuf.get_bits(dtag_length, position=frag_rule[T_RULEIDLENGTH]) else: dtag = None # XXX: get_bits(0) should work? rule_id = frag_rule[T_RULEID] rule_id_length = frag_rule[T_RULEIDLENGTH] session_id = (sender_l2_address, rule_id, rule_id_length, dtag) session = self.session_manager.find_session(session_id) if session is not None: dprint("{} session found".format( session.get_session_type().capitalize()), session.__class__.__name__) else: context = None session = self.session_manager.create_reassembly_session( context, frag_rule, session_id) dprint("New reassembly session created", session.__class__.__name__) session.receive_frag(packet_bbuf, dtag)
def initialize(init_time=None): """Class to initializa the static class creates the file to write and the instance of the class """ dprint('Init statsct module') if init_time is None: init_time = time.time() # XXX: need refactor, should be obtained from Scheduler Statsct.results['init_time'] = init_time #utime.time() -->exception Statsct.results['packet_list'] = [] Statsct.sender_packets['packet_list'] = [] Statsct.receiver_packets['packet_list'] = [] Statsct.src_id = None Statsct.dst_id = None Statsct.device_rule = dict() Statsct.gw_rule = dict() Statsct.gw_rule['fragSender'] = [] Statsct.channel_occupancy = 0 Statsct.goodput = 0 Statsct.total_delay = 0 Statsct.reliability = 0 Statsct.total_packet_send = dict() Statsct.msg_type = "" Statsct.packet_info = dict() Statsct.last_msg_type = "" Statsct.succ_packets = 0 Statsct.fail_packets = 0 Statsct.total_data_send = 0 Statsct.msg_type_queue = [] Statsct.channel_occupancy_sender = 0 Statsct.channel_occupancy_receiver = 0
def get_mic(self, mic_base, last_frag_base_size, penultimate_size=0): assert isinstance(mic_base, BitBuffer) # calculate the significant padding bits. # 1. get the extra bits. # # |<------------ last SCHC frag ------------->| # |<- header ->|<- payload ->|<--- padding -->| # |<---- frag base size ---->|<- extra bits-->| # L2Word ->| extra_bits = (frag_msg.roundup(last_frag_base_size, self.l2word) - last_frag_base_size) # 2. round up the payload of all SCHC fragments # to the MIC word size. # # |<----------------- input data ----------------->| # |<- a SCHC packet ->|<- extra bits->|<- padding ->| # MIC Word ->| MIC Word ->| mic_base.add_bits(0, extra_bits) # XXX if penultimate_size != 0: extra_bits = (frag_msg.roundup(penultimate_size, self.l2word) - penultimate_size) mic_base.add_bits( 0, frag_msg.roundup(extra_bits, self.rule[T_FRAG][T_FRAG_PROF][T_FRAG_MIC])) # mic = get_mic(mic_base.get_content()).to_bytes(4, "big") dprint("Send MIC {}, base = {}, lenght = {}".format( mic.hex(), mic_base.get_content(), len(mic_base.get_content()))) return mic
def _send_packetX_hack(self): self.ACK_SUCCESS = "ACK_SUCCESS" # XXX: this should not be here self.ACK_FAILURE = "ACK_FAILURE" self.RECEIVER_ABORT = "RECEIVER_ABORT" self.SEND_ALL_1 = "SEND_ALL_1" self.WAITING_FOR_ACK = "WAITING_FOR_ACK" self.ACK_TIMEOUT = "ACK_TIMEOUT" count = 1 # for link in link_list: # count += self.send_packet_on_link(link, packet) note_table_list = list(self.node_table.items())[-1][1] #self.node_table[0].protocol.layer2.clientSend.send(packet) note_table_list.protocol.layer2.roleSend.send(packet) # XXX: should not be changed try: number_tiles_send = \ note_table_list.protocol.fragment_session.session_list[0]["session"].current_number_tiles_sent() state = note_table_list.protocol.fragment_session.session_list[0]["session"].state dprint("STATE : ", state) dprint("Lenght queue", len(self.scheduler.queue)) if (state == self.SEND_ALL_1 or state == self.ACK_FAILURE or state == self.ACK_TIMEOUT) \ and number_tiles_send == 0: dprint("------------------------------- RECEIVE PACKET ------------------------------") message = note_table_list.protocol.layer2.roleSend.Receive() # XXX: should not be here dprint("Message from Server", message) note_table_list.protocol.layer2.event_receive_packet(note_table_list.id, message) # note_table_list1.protocol.fragment_session.session_list[0]["session"].state = 'START' except: dprint("Not fragment state")
def test1(): def compress_bitmap_str(b): i = len(b) while i > 0: if b[i - 1] == "0": break i -= 1 return b[:i + 1] def gen_bits_str(N): if N < 1: return "" if N == 1: yield "0" yield "1" else: p = (1 << N) - 2 # 2, 6, 14 for i in range(p + 1): yield "1" * i + "0" + "1" * (p - i) yield "1" * (p + 1) for n in range(5): for i in gen_bits_str(n): dprint(i, compress_bitmap_str(i))
def compress(self, rule, parsed_packet, data, direction=T_DIR_UP): """ Take a compression rule and a parsed packet and return a SCHC pkt """ assert direction in [T_DIR_UP, T_DIR_DW] output_bbuf = BitBuffer() # set ruleID first. if rule[T_RULEID] is not None and rule[T_RULEIDLENGTH] is not None: output_bbuf.add_bits(rule[T_RULEID], rule[T_RULEIDLENGTH]) dprint("rule {}/{}".format(rule[T_RULEID], rule[T_RULEIDLENGTH])) #output_bbuf.display(format="bin") for r in rule["Compression"]: dprint("rule item:", r) if r[T_DI] in [T_DIR_BI, direction]: if (r[T_FID], r[T_FP]) in parsed_packet: dprint("in packet") self.__func_tx_cda[r[T_CDA]](field=parsed_packet[(r[T_FID], r[T_FP])], rule = r, output= output_bbuf) else: # not find in packet, but is variable length can be coded as 0 dprint("send variable length") self.__func_tx_cda[T_CDA_VAL_SENT](field = [0, 0, "Null Field"], rule = r, output = output_bbuf) else: dprint("rule skipped, bad direction") #output_bbuf.display(format="bin") output_bbuf.add_bytes(data) return output_bbuf
def test2(): def gen_bits(N): # if N < 1: return None if N == 1: b = BitBuffer() b.set_bit(0) yield b b = BitBuffer() b._wpos = 0 b.set_bit(1) yield b else: p = (1 << N) - 2 for i in range(p + 1): b = BitBuffer() b.add_bits(pow(2, i) - 1, i) b.set_bit(0) b.add_bits(pow(2, p - i) - 1, p - i) yield b b = BitBuffer() b.add_bits(pow(2, p + 1) - 1, p + 1) yield b for n in range(5): dprint("n=", n) for i in gen_bits(n): dprint(i, compress_bitmap(i))
def resend_frag(self, schc_frag): self.resend = True dprint("recv bitmap:", (schc_frag.win, schc_frag.bitmap.to_bit_list())) dprint("sent bitmap:", (schc_frag.win, self.bit_list[schc_frag.win])) self.all_tiles.unset_sent_flag(schc_frag.win, schc_frag.bitmap.to_bit_list()) self.send_frag()
def cancel_ack_wait_timer(self): # don't assert here because the receiver sends ACK back anytime. #assert self.event_id_ack_wait_timer is not None dprint( '----------------------- cancel_ack_wait_timer -----------------------' ) self.protocol.scheduler.cancel_event(self.event_id_ack_wait_timer) self.event_id_ack_wait_timer = None
def log(self, name, message): if not self.simul_config.get("log", False): return line = "{} [{}] ".format(self.scheduler.get_clock(), name) + message dprint(line) if self.log_file is not None: self.log_file.write(line+"\n") if self.observer is not None: self.observer.record_log(line)
def tiles_send(self): for tile in self.all_tiles.get_all_tiles(): if not tile['sent']: self.number_tiles_send += 1 self.number_tiles_send = math.ceil( self.number_tiles_send / (self.protocol.layer2.get_mtu_size() // self.rule[T_FRAG][T_FRAG_PROF][T_FRAG_TILE])) dprint("----------- ", self.number_tiles_send, "tiles to send")
def add_event(self, rel_time, callback, args): dprint("Add event {}".format(sanitize_value(self.queue))) dprint("callback set -> {}".format(callback.__name__)) assert rel_time >= 0 event_id = self.next_event_id self.next_event_id += 1 clock = self.get_clock() abs_time = clock+rel_time self.queue.append((abs_time, event_id, callback, args)) return event_id
def add_event(self, rel_time, callback, args): dprint("Add event {}".format( [e[:-2] + (e[-2].__name__, ) + e[-1:] for e in self.queue])) dprint("callback set -> {}".format(callback.__name__)) assert rel_time >= 0 event_id = self.next_event_id self.next_event_id += 1 clock = self.get_clock() abs_time = clock + rel_time self.queue.append((abs_time, event_id, callback, args)) return event_id
def receive_frag(self, bbuf, dtag): # the ack timer can be cancelled here, because it's been done whether # both rule_id and dtag in the fragment are matched to this session # at process_received_packet(). self.cancel_ack_wait_timer( ) # the timeout is canceled but has to be set # when an ack should be received self.resend = False # schc_frag = frag_msg.frag_sender_rx(self.rule, bbuf) dprint( "----------------------- Sender Frag Received -----------------------" ) dprint("fragment received -> {}".format(schc_frag.__dict__)) if ((self.rule[T_FRAG][T_FRAG_PROF][T_FRAG_W] is None or schc_frag.win == frag_msg.get_win_all_1(self.rule)) and schc_frag.cbit == 1 and schc_frag.remaining.allones() == True): dprint( "----------------------- Receiver Abort rid={} dtag={} -----------------------" .format(self.rule[T_RULEID], self.dtag)) #self.resend = False self.state = self.RECEIVER_ABORT return if schc_frag.cbit == 1: dprint( "----------------------- ACK Success rid={} dtag={} -----------------------" .format(self.rule[T_RULEID], self.dtag)) #self.resend = False self.state = self.ACK_SUCCESS # XXX needs to be reviewed. at least, no one need this log. # try: # f = open("client_server_simulation.txt", "r+") # except IOError: # f = open("client_server_simulation.txt", "w+") # f = open("client_server_simulation.txt", "r+") # content = f.read() # seconds = time. time() # f.seek(0, 0) # f.write(str(int(seconds)) + '\n' + content) # f.close() return if schc_frag.cbit == 0: dprint( "----------------------- ACK Failure rid={} dtag={} -----------------------" .format(self.rule[T_RULEID], self.dtag)) #self.resend = False #self.all1_send = False self.state = self.ACK_FAILURE self.resend_frag(schc_frag) return
def add_event(self, time_in_sec, event_function, event_args): dprint(f"Add event: " f"call in {time_in_sec} sec: " f"{event_function.__name__} {event_args}") assert time_in_sec >= 0 if event_args is None: evnet_id = self.loop.call_later(time_in_sec, event_function) else: evnet_id = self.loop.call_later(time_in_sec, event_function, *event_args) return evnet_id
def create_device(self, rules): dprint("---------Rules Device -----------") rm0 = RuleManager() devaddr1 = DEFAULT_MAC_ADDRESS_TABLE["device"] rm0.Add(device=devaddr1, dev_info=rules) rm0.Print() self.device_rule_manager = rm0 self.device_node = self._make_schc_node(self.sim, rm0, devaddr1, role="device") return self.device_node
def set_packet(self, packet_bbuf): super().set_packet(packet_bbuf) # because draft-18 requires that in No-ACK mode, each fragment must # contain exactly one tile and the tile size must be at least the size # of an L2 Word. dprint(self.rule) min_size = (frag_msg.get_sender_header_size(self.rule) + frag_msg.get_mic_size(self.rule) + self.l2word) if self.protocol.layer2.get_mtu_size() < min_size: raise ValueError( "the MTU={} is not enough to carry the SCHC fragment of No-ACK mode={}" .format(self.protocol.layer2.get_mtu_size(), min_size))
def create_core(self, rules): dprint("---------Rules gw -----------") rm1 = RuleManager() devaddr2 = DEFAULT_MAC_ADDRESS_TABLE["gateway"] rm1.Add(device=devaddr2, dev_info=rules) rm1.Print() self.core_rule_manager = rm1 self.core_node = self._make_schc_node(self.sim, rm1, devaddr2, role="core-server") return self.core_node
def run(self): while len(self.queue) > 0: self.queue.sort() event_info = self.queue.pop(0) self.clock, event_id, callback, args = event_info self.current_event_id = event_id if self.observer is not None: self.observer("sched-pre-event", event_info) callback(*args) if self.observer is not None: self.observer("sched-post-event", event_info) dprint("Queue running event -> {}, callback -> {}".format(event_id, callback.__name__))
def add(self, rule_id, rule_id_size, dtag, session): if self.get(rule_id, rule_id_size, dtag) is not None: dprint( "ERROR: the session rid={}/{} dtag={} exists already".format( rule_id, rule_id_size, dtag)) return False self.session_list.append({ "rule_id": rule_id, "rule_id_size": rule_id_size, "dtag": dtag, "session": session }) return True
def cond_random(rate): if sys.implementation.name == "micropython": #dprint("micropython") random_num = urandom.getrandbits(8)/256 dprint("1000*random_num -> {} < 10 *rate -> {}, Packet Loss Condition is -> {}".format(random_num*1000,10*rate,random_num * 1000 < rate * 10)) #if random.randint(0,1000) <= (1000 * FER) #if random.randint(0,1000) <= FER_RANDOM * 10 #if urandom.getrandbits(8)/256 * 100 < rate: return random_num * 1000 < rate * 10 else: random_num = random.getrandbits(8)/256 dprint("1000*random_num -> {} < 10 *rate -> {}, Packet Loss Condition is -> {}".format(random_num*1000,10*rate,random_num * 1000 < rate * 10)) return random_num * 1000 < rate * 10
def unset_sent_flag_do(wn, tn): if tn is None: # special case. i.e. the last tile. #dont know why it is a special case, if the ALL-1 is received with a tile #then it should always be one, if the tile is consired received by the method #below, then it should not be false #i think the problem is when the sender does not know if it is the last one #so the the bitmap is received with the max_fcn bit on 1, but since there are #less tiles than the max_fcn. it does not look for that bit dprint("last tile case") #self.all_tiles[-1]["sent"] = False return # normal case. counter = 0 dprint('unset_sent_flag_do') for t in self.all_tiles: if t["w-num"] == wn: if t["t-num"] == self.max_fcn - tn: counter += 1 dprint('counter = {}, t-num {}, tn {}'.format( counter, t["t-num"], tn)) t["sent"] = False elif t["t-num"] == self.max_fcn: dprint("t-num {} == max_fcn {}".format( t["t-num"], self.max_fcn))
def __init__(self, rule, packet_bbuf): """ packet_bbuf: BitBuffer containing the SCHC fragment. """ dprint("frag_sender_rx") dprint(packet_bbuf) #input("") self.init_param() self.set_recvbuf(packet_bbuf) self.rule = rule self.rule_id = self.packet_bbuf.get_bits(rule[T_RULEIDLENGTH]) pos = self.rule[T_RULEIDLENGTH] pos += self.parse_dtag() pos += self.parse_win() pos += self.parse_cbit() if self.cbit == 0: pos += self.parse_bitmap() self.remaining = self.packet_bbuf.get_bits_as_buffer()
def no_compress(self, rule, data): """ Take a compression rule and a parsed packet and return a SCHC pkt """ assert T_NO_COMP in rule output_bbuf = BitBuffer() # set ruleID first. if rule[T_RULEID] is not None and rule[T_RULEIDLENGTH] is not None: output_bbuf.add_bits(rule[T_RULEID], rule[T_RULEIDLENGTH]) dprint("rule {}/{}".format(rule[T_RULEID], rule[T_RULEIDLENGTH])) #output_bbuf.display(format="bin") output_bbuf.add_bytes(data) return output_bbuf
def rx_cda_map_sent(self, rule, in_bbuf): # 7.5.5. mapping-sent CDA # The number of bits sent is the minimal size for coding all the # possible indices. size = len(bin(len(rule[T_TV]) - 1)[2:]) val = in_bbuf.get_bits(size) dprint("====>", rule[T_TV][val], len(rule[T_TV][val]), rule[T_FL]) if rule[T_FL] == "var": size = len(rule[T_TV][val]) else: size = rule[T_FL] return [rule[T_TV][val], size]
def ack_timeout(self, *args): self.cancel_ack_wait_timer() dprint("----------------------- ACK timeout ----------------------- ") self.state = self.ACK_TIMEOUT assert len(args) == 2 assert isinstance(args[0], frag_msg.frag_sender_tx) assert isinstance(args[1], int) schc_frag = args[0] win = args[1] self.ack_requests_counter += 1 dprint("ack_requests_counter -> {}".format(self.ack_requests_counter)) if self.ack_requests_counter > max_ack_requests: # sending sender abort. schc_frag = frag_msg.frag_sender_tx_abort(self.rule, self.dtag) """ Changement à corriger args = (schc_frag.packet.get_content(), self.context["devL2Addr"]) """ args = (schc_frag.packet.get_content(), "*") dprint("MESSSAGE TYPE ----> Sent Sender-Abort.", schc_frag.__dict__) if enable_statsct: Statsct.set_msg_type("SCHC_SENDER_ABORT") Statsct.set_header_size( frag_msg.get_sender_header_size(self.rule)) self.protocol.scheduler.add_event(0, self.protocol.layer2.send_packet, args) return # set ack waiting timer self.event_id_ack_wait_timer = self.protocol.scheduler.add_event( self.ack_wait_timer, self.ack_timeout, args) dprint("*******event id {}".format(self.event_id_ack_wait_timer)) schc_frag = frag_msg.frag_sender_ack_req(self.rule, self.dtag, win) if enable_statsct: Statsct.set_msg_type("SCHC_ACK_REQ") # # retransmit MIC. """Changement à corriger args = (schc_frag.packet.get_content(), self.context["devL2Addr"], self.event_sent_frag) """ args = (schc_frag.packet.get_content(), '*', self.event_sent_frag) dprint("MESSSAGE TYPE ----> SCHC ACK REQ frag:", schc_frag.__dict__) self.protocol.scheduler.add_event(0, self.protocol.layer2.send_packet, args) """ waits for all the acks before sending the ack request
def generate_background_traffic(self, G, background_frag_size): self.background_traffic T = get_toa(background_frag_size, Statsct.SF) g = G / T['t_packet'] dprint("g: {}, G:{}, T:{}".format(g, G, T['t_packet'])) for i in range(1000): #aleatoire = machine.rng() #aleatoire2 = aleatoire/(2**24-1) aleatoire = urandom.getrandbits(8) / 256 aleatoire2 = aleatoire / (2**24 - 1) #dprint(aleatoire2) if aleatoire2 != 0: test = -1 * math.log(aleatoire2) / 1 / g self.background_traffic.append((test, test + T['t_packet'])) if enable_statsct: Statsct.set_background_traffic(self.background_traffic)
def decompress(self, schc, rule, direction): assert ("Compression" in rule) schc.set_read_position(0) self.parsed_packet = {} rule_send = schc.get_bits(nb_bits=rule[T_RULEIDLENGTH]) assert (rule_send == rule["RuleID"]) for r in rule["Compression"]: dprint(r) if r[T_DI] in [T_DIR_BI, direction]: full_field = self.__func_rx_cda[r[T_CDA]](r, schc) dprint("<<<", full_field) self.parsed_packet[(r[T_FID], r[T_FP])] = full_field #pprint.pprint (self.parsed_packet) return self.parsed_packet
def _send_packet_from_queue(self): assert not self.is_transmitting assert len(self.packet_queue) > 0 self.is_transmitting = True (packet, src_dev_id, dst_dev_id, transmit_callback) = self.packet_queue.pop(0) dprint("send packet from queue -> {}, {}, {}, {}".format( packet, src_dev_id, dst_dev_id, transmit_callback is None)) if self.role == "client" or self.role == "server": self.sim.send_packetX(packet, src_dev_id, dst_dev_id, self._event_sent_callback, (transmit_callback, )) else: self.sim.send_packet(packet, src_dev_id, dst_dev_id, self._event_sent_callback, (transmit_callback, ))