def _unittest_udp_tracer() -> None: from pytest import approx from ipaddress import ip_address from pyuavcan.transport import Priority, ServiceDataSpecifier from pyuavcan.transport.udp import UDPTransport from ._ip import MACHeader, IPHeader, UDPHeader, service_data_specifier_to_udp_port tr = UDPTransport.make_tracer() ts = Timestamp.now() ds = ServiceDataSpecifier(11, ServiceDataSpecifier.Role.RESPONSE) trace = tr.update( UDPCapture( ts, RawPacket( MACHeader(memoryview(b""), memoryview(b"")), IPHeader(ip_address("127.0.0.42"), ip_address("127.0.0.63")), UDPHeader(12345, service_data_specifier_to_udp_port(ds)), memoryview(b"".join( UDPFrame( priority=Priority.SLOW, transfer_id=1234567890, index=0, end_of_transfer=True, payload=memoryview(b"Hello world!"), ).compile_header_and_payload())), ), )) assert isinstance(trace, TransferTrace) assert trace.timestamp == ts assert trace.transfer_id_timeout == approx( AlienTransferReassembler.MAX_TRANSFER_ID_TIMEOUT) # Initial value. assert trace.transfer.metadata.transfer_id == 1234567890 assert trace.transfer.metadata.priority == Priority.SLOW assert trace.transfer.metadata.session_specifier.source_node_id == 42 assert trace.transfer.metadata.session_specifier.destination_node_id == 63 assert trace.transfer.metadata.session_specifier.data_specifier == ds assert trace.transfer.fragmented_payload == [memoryview(b"Hello world!")] assert None is tr.update( pyuavcan.transport.Capture(ts)) # Another transport, ignored. assert None is tr.update( UDPCapture( # Malformed frame. ts, RawPacket( MACHeader(memoryview(b""), memoryview(b"")), IPHeader(ip_address("127.0.0.42"), ip_address("127.1.0.63")), UDPHeader(1, 1), memoryview(b""), ), ))
def _unittest_udp_tracer() -> None: import socket from pytest import approx from ipaddress import ip_address from pyuavcan.transport import Priority, ServiceDataSpecifier from pyuavcan.transport.udp import UDPTransport from ._ip import service_data_specifier_to_udp_port tr = UDPTransport.make_tracer() ts = Timestamp.now() ds = ServiceDataSpecifier(11, ServiceDataSpecifier.Role.RESPONSE) # VALID SERVICE FRAME llp = LinkLayerPacket( protocol=socket.AF_INET, source=memoryview(b""), destination=memoryview(b""), payload=memoryview(b"".join([ # IPv4 b"\x45\x00", (20 + 8 + 24 + 12).to_bytes( 2, "big"), # Total length (incl. the 20 bytes of the IP header) b"\x7e\x50\x40\x00\x40", # ID, flags, fragment offset, TTL b"\x11", # Protocol (UDP) b"\x00\x00", # IP checksum (unset) ip_address("127.0.0.42").packed, # Source ip_address("127.0.0.63").packed, # Destination # UDP/IP (12345).to_bytes(2, "big"), # Source port service_data_specifier_to_udp_port(ds).to_bytes( 2, "big"), # Destination port (8 + 24 + 12).to_bytes( 2, "big"), # Total length (incl. the 8 bytes of the UDP header) b"\x00\x00", # UDP checksum (unset) # UAVCAN/UDP b"".join( UDPFrame( priority=Priority.SLOW, transfer_id=1234567890, index=0, end_of_transfer=True, payload=memoryview(b"Hello world!"), ).compile_header_and_payload()), ])), ) ip_packet = IPPacket.parse(llp) assert ip_packet is not None assert ip_packet.source_destination == (ip_address("127.0.0.42"), ip_address("127.0.0.63")) assert ip_packet.protocol == 0x11 udp_packet = UDPIPPacket.parse(ip_packet) assert udp_packet is not None assert udp_packet.source_port == 12345 assert udp_packet.destination_port == service_data_specifier_to_udp_port( ds) trace = tr.update(UDPCapture(ts, llp)) assert isinstance(trace, TransferTrace) assert trace.timestamp == ts assert trace.transfer_id_timeout == approx(2.0) # Initial value. assert trace.transfer.metadata.transfer_id == 1234567890 assert trace.transfer.metadata.priority == Priority.SLOW assert trace.transfer.metadata.session_specifier.source_node_id == 42 assert trace.transfer.metadata.session_specifier.destination_node_id == 63 assert trace.transfer.metadata.session_specifier.data_specifier == ds assert trace.transfer.fragmented_payload == [memoryview(b"Hello world!")] # ANOTHER TRANSPORT, IGNORED assert None is tr.update(pyuavcan.transport.Capture(ts)) # MALFORMED - UAVCAN/UDP IS EMPTY llp = LinkLayerPacket( protocol=socket.AF_INET, source=memoryview(b""), destination=memoryview(b""), payload=memoryview(b"".join([ # IPv4 b"\x45\x00", (20 + 8 + 24 + 12).to_bytes( 2, "big"), # Total length (incl. the 20 bytes of the IP header) b"\x7e\x50\x40\x00\x40", # ID, flags, fragment offset, TTL b"\x11", # Protocol (UDP) b"\x00\x00", # IP checksum (unset) ip_address("127.0.0.42").packed, # Source ip_address("127.0.0.63").packed, # Destination # UDP/IP (1).to_bytes(2, "big"), # Source port (1).to_bytes(2, "big"), # Destination port (8).to_bytes( 2, "big"), # Total length (incl. the 8 bytes of the UDP header) b"\x00\x00", # UDP checksum (unset) # UAVCAN/UDP is missing ])), ) ip_packet = IPPacket.parse(llp) assert ip_packet is not None assert ip_packet.source_destination == (ip_address("127.0.0.42"), ip_address("127.0.0.63")) assert ip_packet.protocol == 0x11 udp_packet = UDPIPPacket.parse(ip_packet) assert udp_packet is not None assert udp_packet.source_port == 1 assert udp_packet.destination_port == 1 assert None is tr.update(UDPCapture(ts, llp))