def test_encode_decode_fragment(self): msg = "Hello, World!".encode("utf-8") datagram1 = DatagramHeader(source=100, destination=100, length=len(msg), checksum=crc_b(msg)) fragment1 = FragmentHeader(Protocol.DATAGRAM, FragmentFlags.NONE, 0, 99) header1 = NetworkHeader(version=0, protocol=Protocol.FRAGMENT, qos=QoS.Default, ttl=4, identity=42, length=fragment1.size() + datagram1.size() + len(msg), source=MeshAddress(1), destination=MeshAddress(2)) stream = BytesIO() header1.encode(stream) fragment1.encode(stream) datagram1.encode(stream) stream.write(msg) stream.seek(0) header2 = NetworkHeader.decode(stream) fragment = FragmentHeader.decode(stream) datagram = DatagramHeader.decode(stream) msg2 = stream.read() self.assertEqual(header1, header2) self.assertEqual(datagram1, datagram) self.assertEqual(msg2, msg)
def test_encode_decode_datagram(self): msg = "Hello, World!".encode("utf-8") datagram_header_1 = DatagramHeader(source=100, destination=100, length=len(msg), checksum=crc_b(msg)) header1 = NetworkHeader(version=0, protocol=Protocol.DATAGRAM, qos=QoS.Default, ttl=4, identity=42, length=datagram_header_1.size() + len(msg), source=MeshAddress(1), destination=MeshAddress(2)) data = encode_packet(header1, [datagram_header_1], msg) stream = BytesIO(data) header2 = NetworkHeader.decode(stream) datagram2 = DatagramHeader.decode(stream) self.assertEqual(header1, header2) self.assertEqual(datagram_header_1, datagram2)
def check_acks(self): with self.not_empty: while len(self.sent) == 0: self.not_empty.wait() item = self.sent[0] item.attempt += 1 if item.attempt > ReliableManager.MaxResend: self.info(f"Expiring {item}") self.sent.remove(item) self.network.failed_send(item.header.destination) self.not_full.notify() else: self.info(f"Resending {item}") stream = BytesIO(item.buffer) network_header = NetworkHeader.decode(stream) network_header = dataclasses.replace( network_header, identity=self.network.next_sequence()) stream.seek(0) network_header.encode(stream) stream.seek(0) self.network.send(network_header, stream.read()) # TODO backoff self.timer.reset()
def process_incoming(self, payload: L2Payload): stream = BytesIO(payload.l3_data) try: network_header = NetworkHeader.decode(stream) except Exception as e: self.error(f"Could not decode network packet from {payload}.", e) return # Handle L3 protocols first if network_header.destination == self.our_address and network_header.protocol == Protocol.CONTROL: ctrl = ControlHeader.decode(stream) self.info(f"Got {ctrl} from {network_header.source}") if ctrl.control_type == ControlType.PING: self.ping_protocol.handle_ping(network_header, ctrl) else: self.warning( f"Ignoring unsupported control packet: {ctrl.control_type}" ) return if network_header.protocol == Protocol.HELLO: self.handle_hello(payload.link_id, network_header, HelloHeader.decode(stream)) return if network_header.protocol == Protocol.LINK_STATE: self.handle_advertisement( payload.link_id, network_header, LinkStateAdvertisementHeader.decode(stream)) return if network_header.protocol == Protocol.LINK_STATE_QUERY: self.handle_query(payload.link_id, network_header, LinkStateQueryHeader.decode(stream)) return # Now decide if we should handle or drop if self.header_cache.contains(hash(network_header)): self.debug(f"Dropping duplicate {network_header}") return # If the packet is addressed to us, handle it if network_header.destination == self.our_address: self.debug(f"Handling {network_header}") self.l4_handlers.handle_l4(network_header, network_header.protocol, stream) return if network_header.destination == self.BroadcastAddress: self.debug(f"Handling broadcast {network_header}") self.l4_handlers.handle_l4(network_header, network_header.protocol, stream) if network_header.ttl > 1: # Decrease the TTL and re-broadcast on all links except where we heard it header_copy = dataclasses.replace(network_header, ttl=network_header.ttl - 1) stream.seek(0) header_copy.encode(stream) stream.seek(0) self.send(header_copy, stream.read(), exclude_link_id=payload.link_id) else: self.debug("Not re-broadcasting due to TTL") else: header_copy = dataclasses.replace(network_header, ttl=network_header.ttl - 1) stream.seek(0) header_copy.encode(stream) stream.seek(0) self.send(header_copy, stream.read(), exclude_link_id=payload.link_id)