def datagram_received(self, datagram, addr): buf = Buffer(data=datagram) header = pull_quic_header(buf, host_cid_length=8) # version negotiation if (header.version is not None and header.version not in QuicConnection.supported_versions): self._transport.sendto( encode_quic_version_negotiation( source_cid=header.destination_cid, destination_cid=header.source_cid, supported_versions=QuicConnection.supported_versions, ), addr, ) return connection = self._connections.get(header.destination_cid, None) if connection is None and header.packet_type == PACKET_TYPE_INITIAL: # create new connection connection = QuicConnection(is_client=False, **self._kwargs) connection.connection_made(QuicConnectionTransport(self, addr)) connection.stream_created_cb = self.stream_created self._connections[connection.host_cid] = connection logger.info("%s New connection from %s" % (connection_id(connection), addr)) if connection is not None: connection.datagram_received(datagram, addr)
def test_pull_initial_server(self): buf = Buffer(data=load("initial_server.bin")) header = pull_quic_header(buf, host_cid_length=8) self.assertTrue(header.is_long_header) self.assertEqual(header.version, QuicProtocolVersion.DRAFT_17) self.assertEqual(header.packet_type, PACKET_TYPE_INITIAL) self.assertEqual(header.destination_cid, b"") self.assertEqual(header.source_cid, binascii.unhexlify("0fcee9852fde8780")) self.assertEqual(header.original_destination_cid, b"") self.assertEqual(header.token, b"") self.assertEqual(header.rest_length, 182) self.assertEqual(buf.tell(), 17)
def test_pull_short_header(self): buf = Buffer(data=load("short_header.bin")) header = pull_quic_header(buf, host_cid_length=8) self.assertFalse(header.is_long_header) self.assertEqual(header.version, None) self.assertEqual(header.packet_type, 0x50) self.assertEqual(header.destination_cid, binascii.unhexlify("f45aa7b59c0e1ad6")) self.assertEqual(header.source_cid, b"") self.assertEqual(header.original_destination_cid, b"") self.assertEqual(header.token, b"") self.assertEqual(header.rest_length, 12) self.assertEqual(buf.tell(), 9)
def test_pull_version_negotiation(self): buf = Buffer(data=load("version_negotiation.bin")) header = pull_quic_header(buf, host_cid_length=8) self.assertTrue(header.is_long_header) self.assertEqual(header.version, QuicProtocolVersion.NEGOTIATION) self.assertEqual(header.packet_type, None) self.assertEqual(header.destination_cid, binascii.unhexlify("dae1889b81a91c26")) self.assertEqual(header.source_cid, binascii.unhexlify("f49243784f9bf3be")) self.assertEqual(header.original_destination_cid, b"") self.assertEqual(header.token, b"") self.assertEqual(header.rest_length, 8) self.assertEqual(buf.tell(), 22)
def test_pull_retry(self): buf = Buffer(data=load("retry.bin")) header = pull_quic_header(buf, host_cid_length=8) self.assertTrue(header.is_long_header) self.assertEqual(header.version, QuicProtocolVersion.DRAFT_19) self.assertEqual(header.packet_type, PACKET_TYPE_RETRY) self.assertEqual(header.destination_cid, binascii.unhexlify("c98343fe8f5f0ff4")) self.assertEqual( header.source_cid, binascii.unhexlify("c17f7c0473e635351b85a17e9f3296d7246c"), ) self.assertEqual(header.original_destination_cid, binascii.unhexlify("85abb547bf28be97")) self.assertEqual( header.token, binascii.unhexlify( "01652d68d17c8e9f968d4fb4b70c9e526c4f837dbd85abb547bf28be97"), ) self.assertEqual(header.rest_length, 0) self.assertEqual(buf.tell(), 69)
def test_pull_empty(self): buf = Buffer(data=b"") with self.assertRaises(BufferReadError): pull_quic_header(buf, host_cid_length=8)
def test_pull_short_header_no_fixed_bit(self): buf = Buffer(data=b"\x00") with self.assertRaises(ValueError) as cm: pull_quic_header(buf, host_cid_length=8) self.assertEqual(str(cm.exception), "Packet fixed bit is zero")
def test_pull_long_header_too_short(self): buf = Buffer(data=b"\xc0\x00") with self.assertRaises(BufferReadError): pull_quic_header(buf, host_cid_length=8)
def datagram_received(self, data: Union[bytes, Text], addr: NetworkAddress) -> None: data = cast(bytes, data) buf = Buffer(data=data) header = pull_quic_header(buf, host_cid_length=8) # version negotiation if (header.version is not None and header.version not in self._configuration.supported_versions): self._transport.sendto( encode_quic_version_negotiation( source_cid=header.destination_cid, destination_cid=header.source_cid, supported_versions=self._configuration.supported_versions, ), addr, ) return connection = self._connections.get(header.destination_cid, None) original_connection_id: Optional[bytes] = None if connection is None and header.packet_type == PACKET_TYPE_INITIAL: # stateless retry if self._retry is not None: if not header.token: # create a retry token self._transport.sendto( encode_quic_retry( version=header.version, source_cid=os.urandom(8), destination_cid=header.source_cid, original_destination_cid=header.destination_cid, retry_token=self._retry.create_token( addr, header.destination_cid), ), addr, ) return else: # validate retry token try: original_connection_id = self._retry.validate_token( addr, header.token) except ValueError: return # create new connection connection = QuicConnection( configuration=self._configuration, original_connection_id=original_connection_id, session_ticket_fetcher=self._session_ticket_fetcher, session_ticket_handler=self._session_ticket_handler, ) self._connections[header.destination_cid] = connection self._connections[connection.host_cid] = connection if connection is not None: connection.receive_datagram(cast(bytes, data), addr, now=self._loop.time()) self._consume_events(connection)