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 handle_l4(self, network_header: NetworkHeader, stream: BytesIO): fragment_header = FragmentHeader.decode(stream) fragment = Fragment(network_header, fragment_header, stream.read()) source = fragment.network_header.source dest = fragment.network_header.destination protocol = fragment.fragment_header.protocol # Only Datagram allowed inside fragments (for now) if protocol != Protocol.DATAGRAM: self.warning( f"Dropping fragment for unsupport protocol {protocol}") # The sequence minus fragment is same for all fragments in a given PDU base_seq = ( MeshProtocol.WindowSize + fragment.fragment_header.sequence - fragment.fragment_header.fragment) % MeshProtocol.WindowSize # Buffer the incoming frame and see if it completes a whole segment self.buffer[source][base_seq].append(fragment) fragments = self.buffer[source][base_seq] sorted_fragments = sorted( fragments, key=operator.attrgetter("fragment_header.fragment")) has_more = sorted_fragments[ -1].fragment_header.flags & FragmentFlags.FRAGMENT have_all = len( fragments) == sorted_fragments[-1].fragment_header.fragment + 1 if not has_more and have_all: del self.buffer[source][base_seq] joined = BytesIO() for fragment in sorted_fragments: if fragment.network_header.source == source and \ fragment.network_header.destination == dest and \ fragment.fragment_header.protocol == protocol: joined.write(fragment.payload) else: # Fragment consistency error raise RuntimeError( "Fragment consistency error, header fields do not match" ) joined.seek(0) datagram_header = DatagramHeader.decode(joined) payload = joined.read() self.datagram_manager.handle_datagram( Datagram(fragment.network_header, datagram_header, payload))
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 handle_l4(self, network_header: NetworkHeader, stream: BytesIO): nonlocal captured DatagramHeader.decode(stream) captured = stream.read()
def handle_l4(self, network_header: NetworkHeader, stream: BytesIO): datagram_header = DatagramHeader.decode(stream) self.datagram_manager.handle_datagram( Datagram(network_header, datagram_header, stream.read()))