def test_handshake_error( self, mock_err_get_error, mock_ssl_get_error, mock_do_handshake ): mock_err_get_error.side_effect = [0x2006D080, 0, 0] mock_ssl_get_error.return_value = 1 mock_do_handshake.return_value = -1 transport1, transport2 = dummy_ice_transport_pair() certificate1 = RTCCertificate.generateCertificate() session1 = RTCDtlsTransport(transport1, [certificate1]) certificate2 = RTCCertificate.generateCertificate() session2 = RTCDtlsTransport(transport2, [certificate2]) run( asyncio.gather( session1.start(session2.getLocalParameters()), session2.start(session1.getLocalParameters()), ) ) self.assertEqual(session1.state, "failed") self.assertEqual(session2.state, "failed") run(session1.stop()) run(session2.stop())
def test_abrupt_disconnect(self): transport1, transport2 = dummy_ice_transport_pair() certificate1 = RTCCertificate.generateCertificate() session1 = RTCDtlsTransport(transport1, [certificate1]) certificate2 = RTCCertificate.generateCertificate() session2 = RTCDtlsTransport(transport2, [certificate2]) run( asyncio.gather( session1.start(session2.getLocalParameters()), session2.start(session1.getLocalParameters()), ) ) # break connections -> tasks exits run(transport1.stop()) run(transport2.stop()) # close DTLS run(session1.stop()) run(session2.stop()) # check outcome self.assertEqual(session1.state, "closed") self.assertEqual(session2.state, "closed")
def test_abrupt_disconnect_during_recv(self): transport1, transport2 = dummy_ice_transport_pair() certificate1 = RTCCertificate.generateCertificate() session1 = RTCDtlsTransport(transport1, [certificate1]) certificate2 = RTCCertificate.generateCertificate() session2 = RTCDtlsTransport(transport2, [certificate2]) run( asyncio.gather(session1.start(session2.getLocalParameters()), session2.start(session1.getLocalParameters()))) # break one connection with self.assertRaises(ConnectionError): run(asyncio.gather(session1.data.recv(), transport1.stop())) self.assertEqual(session1.state, 'closed') # break other connection with self.assertRaises(ConnectionError): run(asyncio.gather(session2.data.recv(), transport2.stop())) self.assertEqual(session2.state, 'closed') # try closing again run(session1.stop()) run(session2.stop())
def test_bad_client_fingerprint(self): transport1, transport2 = dummy_ice_transport_pair() certificate1 = RTCCertificate.generateCertificate() session1 = RTCDtlsTransport(transport1, [certificate1]) certificate2 = RTCCertificate.generateCertificate() session2 = RTCDtlsTransport(transport2, [certificate2]) bogus_parameters = RTCDtlsParameters( fingerprints=[ RTCDtlsFingerprint(algorithm="sha-256", value="bogus_fingerprint") ] ) run( asyncio.gather( session1.start(bogus_parameters), session2.start(session1.getLocalParameters()), ) ) self.assertEqual(session1.state, "failed") self.assertEqual(session2.state, "connected") run(session1.stop()) run(session2.stop())
async def test_abrupt_disconnect_2(self): transport1, transport2 = dummy_ice_transport_pair() certificate1 = RTCCertificate.generateCertificate() session1 = RTCDtlsTransport(transport1, [certificate1]) certificate2 = RTCCertificate.generateCertificate() session2 = RTCDtlsTransport(transport2, [certificate2]) await asyncio.gather( session1.start(session2.getLocalParameters()), session2.start(session1.getLocalParameters()), ) def fake_write_ssl(): raise ConnectionError session1._write_ssl = fake_write_ssl # close DTLS -> ConnectionError await session1.stop() await session2.stop() await asyncio.sleep(0.1) # check outcome self.assertEqual(session1.state, "closed") self.assertEqual(session2.state, "closed")
def test_rtp_malformed(self): transport1, transport2 = dummy_ice_transport_pair() certificate1 = RTCCertificate.generateCertificate() session1 = RTCDtlsTransport(transport1, [certificate1]) # receive truncated RTP run(session1._handle_rtp_data(RTP[0:8], 0)) # receive truncated RTCP run(session1._handle_rtcp_data(RTCP[0:8]))
def test_lossy_channel(self): transport1, transport2 = dummy_ice_transport_pair(loss=0.3) certificate1 = RTCCertificate.generateCertificate() session1 = RTCDtlsTransport(transport1, [certificate1]) certificate2 = RTCCertificate.generateCertificate() session2 = RTCDtlsTransport(transport2, [certificate2]) run( asyncio.gather(session1.start(session2.getLocalParameters()), session2.start(session1.getLocalParameters()))) run(session1.stop()) run(session2.stop())
def dummy_dtls_transport_pair(): ice_a, ice_b = dummy_ice_transport_pair() dtls_a = RTCDtlsTransport(ice_a, [RTCCertificate.generateCertificate()]) dtls_b = RTCDtlsTransport(ice_b, [RTCCertificate.generateCertificate()]) run( asyncio.gather(dtls_b.start(dtls_a.getLocalParameters()), dtls_a.start(dtls_b.getLocalParameters()))) return (dtls_a, dtls_b)
def test_broken_ssl(self, mock_use_certificate): mock_use_certificate.return_value = 0 transport1, transport2 = dummy_ice_transport_pair() certificate = RTCCertificate.generateCertificate() with self.assertRaises(DtlsError): RTCDtlsTransport(transport1, [certificate])
def test_lossy_channel(self): """ Transport with 25% loss eventually connects. """ transport1, transport2 = dummy_ice_transport_pair(loss=[True, False, False, False]) certificate1 = RTCCertificate.generateCertificate() session1 = RTCDtlsTransport(transport1, [certificate1]) certificate2 = RTCCertificate.generateCertificate() session2 = RTCDtlsTransport(transport2, [certificate2]) run(asyncio.gather( session1.start(session2.getLocalParameters()), session2.start(session1.getLocalParameters()))) run(session1.stop()) run(session2.stop())
async def dummy_dtls_transport_pair(): ice_a, ice_b = dummy_ice_transport_pair() dtls_a = RTCDtlsTransport(ice_a, [RTCCertificate.generateCertificate()]) dtls_b = RTCDtlsTransport(ice_b, [RTCCertificate.generateCertificate()]) await asyncio.gather( dtls_b.start(dtls_a.getLocalParameters()), dtls_a.start(dtls_b.getLocalParameters()), ) try: yield (dtls_a, dtls_b) finally: await dtls_a.stop() await dtls_b.stop()
def test_handshake_error(self, mock_get_error, mock_do_handshake): mock_get_error.return_value = 1 mock_do_handshake.return_value = -1 transport1, transport2 = dummy_ice_transport_pair() certificate1 = RTCCertificate.generateCertificate() session1 = RTCDtlsTransport(transport1, [certificate1]) certificate2 = RTCCertificate.generateCertificate() session2 = RTCDtlsTransport(transport2, [certificate2]) with self.assertRaises(DtlsError) as cm: run( asyncio.gather(session1.start(session2.getLocalParameters()), session2.start(session1.getLocalParameters()))) self.assertEqual(str(cm.exception), 'DTLS handshake failed (error 1)') self.assertEqual(session1.state, 'failed') self.assertEqual(session2.state, 'failed') run(session1.stop()) run(session2.stop())
def test_bad_client_fingerprint(self): transport1, transport2 = dummy_ice_transport_pair() certificate1 = RTCCertificate.generateCertificate() session1 = RTCDtlsTransport(transport1, [certificate1]) certificate2 = RTCCertificate.generateCertificate() session2 = RTCDtlsTransport(transport2, [certificate2]) bogus_parameters = RTCDtlsParameters( fingerprints=[RTCDtlsFingerprint(algorithm='sha-256', value='bogus_fingerprint')]) with self.assertRaises(DtlsError) as cm: run(asyncio.gather( session1.start(bogus_parameters), session2.start(session1.getLocalParameters()))) self.assertEqual(str(cm.exception), 'DTLS fingerprint does not match') self.assertEqual(session1.state, 'failed') self.assertEqual(session2.state, 'connecting') run(session1.stop()) run(session2.stop())
async def test_lossy_channel(self): """ Transport with 25% loss eventually connects. """ transport1, transport2 = dummy_ice_transport_pair() loss_pattern = [True, False, False, False] transport1._connection.loss_pattern = loss_pattern transport2._connection.loss_pattern = loss_pattern certificate1 = RTCCertificate.generateCertificate() session1 = RTCDtlsTransport(transport1, [certificate1]) certificate2 = RTCCertificate.generateCertificate() session2 = RTCDtlsTransport(transport2, [certificate2]) await asyncio.gather( session1.start(session2.getLocalParameters()), session2.start(session1.getLocalParameters()), ) await session1.stop() await session2.stop()
def test_data(self): transport1, transport2 = dummy_ice_transport_pair() certificate1 = RTCCertificate.generateCertificate() session1 = RTCDtlsTransport(transport1, [certificate1]) certificate2 = RTCCertificate.generateCertificate() session2 = RTCDtlsTransport(transport2, [certificate2]) run( asyncio.gather(session1.start(session2.getLocalParameters()), session2.start(session1.getLocalParameters()))) # send encypted data run(session1.data.send(b'ping')) data = run(session2.data.recv()) self.assertEqual(data, b'ping') run(session2.data.send(b'pong')) data = run(session1.data.recv()) self.assertEqual(data, b'pong') # shutdown run(session1.stop()) run(asyncio.sleep(0.5)) self.assertEqual(session1.state, 'closed') self.assertEqual(session2.state, 'closed') # try closing again run(session1.stop()) run(session2.stop()) # try receving after close with self.assertRaises(ConnectionError): run(session1.data.recv()) # try sending after close with self.assertRaises(ConnectionError): run(session1.data.send(b'foo'))
def test_broken_ssl(self, mock_use_certificate): mock_use_certificate.return_value = 0 certificate = RTCCertificate.generateCertificate() with self.assertRaises(DtlsError): RTCDtlsTransport(None, [certificate])
def test_srtp_unprotect_error(self): transport1, transport2 = dummy_ice_transport_pair() certificate1 = RTCCertificate.generateCertificate() session1 = RTCDtlsTransport(transport1, [certificate1]) receiver1 = DummyRtpReceiver() session1._register_rtp_receiver( receiver1, RTCRtpParameters(rtcp=RTCRtcpParameters(ssrc=1831097322))) certificate2 = RTCCertificate.generateCertificate() session2 = RTCDtlsTransport(transport2, [certificate2]) receiver2 = DummyRtpReceiver() session2._register_rtp_receiver( receiver2, RTCRtpParameters(rtcp=RTCRtcpParameters(ssrc=4028317929))) run( asyncio.gather(session1.start(session2.getLocalParameters()), session2.start(session1.getLocalParameters()))) # send same RTP twice, to trigger error on the receiver side: # "replay check failed (bad index)" run(session1._send_rtp(RTP)) run(session1._send_rtp(RTP)) run(asyncio.sleep(0.5)) self.assertEqual(len(receiver2.rtcp_packets), 0) self.assertEqual(len(receiver2.rtp_packets), 1) # shutdown run(session1.stop()) run(session2.stop())
def test_rtp(self): transport1, transport2 = dummy_ice_transport_pair() certificate1 = RTCCertificate.generateCertificate() session1 = RTCDtlsTransport(transport1, [certificate1]) receiver1 = DummyRtpReceiver() session1._register_rtp_receiver( receiver1, RTCRtpParameters(rtcp=RTCRtcpParameters(ssrc=1831097322))) certificate2 = RTCCertificate.generateCertificate() session2 = RTCDtlsTransport(transport2, [certificate2]) receiver2 = DummyRtpReceiver() session2._register_rtp_receiver( receiver2, RTCRtpParameters(rtcp=RTCRtcpParameters(ssrc=4028317929))) run( asyncio.gather(session1.start(session2.getLocalParameters()), session2.start(session1.getLocalParameters()))) # send RTP run(session1._send_rtp(RTP)) run(asyncio.sleep(0.1)) self.assertEqual(len(receiver2.rtcp_packets), 0) self.assertEqual(len(receiver2.rtp_packets), 1) # send RTCP run(session2._send_rtp(RTCP)) run(asyncio.sleep(0.1)) self.assertEqual(len(receiver1.rtcp_packets), 1) self.assertEqual(len(receiver1.rtp_packets), 0) # shutdown run(session1.stop()) run(asyncio.sleep(0.5)) self.assertEqual(session1.state, 'closed') self.assertEqual(session2.state, 'closed') # try closing again run(session1.stop()) run(session2.stop()) # try sending after close with self.assertRaises(ConnectionError): run(session1._send_rtp(RTP))
def test_data(self): transport1, transport2 = dummy_ice_transport_pair() certificate1 = RTCCertificate.generateCertificate() session1 = RTCDtlsTransport(transport1, [certificate1]) receiver1 = DummyDataReceiver() session1._register_data_receiver(receiver1) certificate2 = RTCCertificate.generateCertificate() session2 = RTCDtlsTransport(transport2, [certificate2]) receiver2 = DummyDataReceiver() session2._register_data_receiver(receiver2) run( asyncio.gather(session1.start(session2.getLocalParameters()), session2.start(session1.getLocalParameters()))) # send encypted data run(session1._send_data(b'ping')) run(asyncio.sleep(0.1)) self.assertEqual(receiver2.data, [b'ping']) run(session2._send_data(b'pong')) run(asyncio.sleep(0.1)) self.assertEqual(receiver1.data, [b'pong']) # shutdown run(session1.stop()) run(asyncio.sleep(0.5)) self.assertEqual(session1.state, 'closed') self.assertEqual(session2.state, 'closed') # try closing again run(session1.stop()) run(session2.stop()) # try sending after close with self.assertRaises(ConnectionError): run(session1._send_data(b'foo'))
def test_srtp_unprotect_error(self): transport1, transport2 = dummy_ice_transport_pair() certificate1 = RTCCertificate.generateCertificate() session1 = RTCDtlsTransport(transport1, [certificate1]) receiver1 = DummyRtpReceiver() session1._register_rtp_receiver( receiver1, RTCRtpReceiveParameters( codecs=[ RTCRtpCodecParameters( mimeType="audio/PCMU", clockRate=8000, payloadType=0 ) ], encodings=[RTCRtpDecodingParameters(ssrc=1831097322, payloadType=0)], ), ) certificate2 = RTCCertificate.generateCertificate() session2 = RTCDtlsTransport(transport2, [certificate2]) receiver2 = DummyRtpReceiver() session2._register_rtp_receiver( receiver2, RTCRtpReceiveParameters( codecs=[ RTCRtpCodecParameters( mimeType="audio/PCMU", clockRate=8000, payloadType=0 ) ], encodings=[RTCRtpDecodingParameters(ssrc=4028317929, payloadType=0)], ), ) run( asyncio.gather( session1.start(session2.getLocalParameters()), session2.start(session1.getLocalParameters()), ) ) # send same RTP twice, to trigger error on the receiver side: # "replay check failed (bad index)" run(session1._send_rtp(RTP)) run(session1._send_rtp(RTP)) run(asyncio.sleep(0.1)) self.assertEqual(len(receiver2.rtcp_packets), 0) self.assertEqual(len(receiver2.rtp_packets), 1) # shutdown run(session1.stop()) run(session2.stop())
async def test_data(self): transport1, transport2 = dummy_ice_transport_pair() certificate1 = RTCCertificate.generateCertificate() session1 = RTCDtlsTransport(transport1, [certificate1]) receiver1 = DummyDataReceiver() session1._register_data_receiver(receiver1) certificate2 = RTCCertificate.generateCertificate() session2 = RTCDtlsTransport(transport2, [certificate2]) receiver2 = DummyDataReceiver() session2._register_data_receiver(receiver2) await asyncio.gather( session1.start(session2.getLocalParameters()), session2.start(session1.getLocalParameters()), ) # send encypted data await session1._send_data(b"ping") await asyncio.sleep(0.1) self.assertEqual(receiver2.data, [b"ping"]) await session2._send_data(b"pong") await asyncio.sleep(0.1) self.assertEqual(receiver1.data, [b"pong"]) # shutdown await session1.stop() await asyncio.sleep(0.1) self.assertEqual(session1.state, "closed") self.assertEqual(session2.state, "closed") # try closing again await session1.stop() await session2.stop() # try sending after close with self.assertRaises(ConnectionError): await session1._send_data(b"foo")
def test_rtp(self): transport1, transport2 = dummy_ice_transport_pair() certificate1 = RTCCertificate.generateCertificate() session1 = RTCDtlsTransport(transport1, [certificate1]) receiver1 = DummyRtpReceiver() session1._register_rtp_receiver( receiver1, RTCRtpReceiveParameters( codecs=[ RTCRtpCodecParameters( mimeType="audio/PCMU", clockRate=8000, payloadType=0 ) ], encodings=[RTCRtpDecodingParameters(ssrc=1831097322, payloadType=0)], ), ) certificate2 = RTCCertificate.generateCertificate() session2 = RTCDtlsTransport(transport2, [certificate2]) receiver2 = DummyRtpReceiver() session2._register_rtp_receiver( receiver2, RTCRtpReceiveParameters( codecs=[ RTCRtpCodecParameters( mimeType="audio/PCMU", clockRate=8000, payloadType=0 ) ], encodings=[RTCRtpDecodingParameters(ssrc=4028317929, payloadType=0)], ), ) run( asyncio.gather( session1.start(session2.getLocalParameters()), session2.start(session1.getLocalParameters()), ) ) self.assertCounters(session1, session2, 2, 2) # send RTP run(session1._send_rtp(RTP)) run(asyncio.sleep(0.1)) self.assertCounters(session1, session2, 3, 2) self.assertEqual(len(receiver2.rtcp_packets), 0) self.assertEqual(len(receiver2.rtp_packets), 1) # send RTCP run(session2._send_rtp(RTCP)) run(asyncio.sleep(0.1)) self.assertCounters(session1, session2, 3, 3) self.assertEqual(len(receiver1.rtcp_packets), 1) self.assertEqual(len(receiver1.rtp_packets), 0) # shutdown run(session1.stop()) run(asyncio.sleep(0.1)) self.assertCounters(session1, session2, 4, 3) self.assertEqual(session1.state, "closed") self.assertEqual(session2.state, "closed") # try closing again run(session1.stop()) run(session2.stop()) # try sending after close with self.assertRaises(ConnectionError): run(session1._send_rtp(RTP))
def test_data_handler_error(self): transport1, transport2 = dummy_ice_transport_pair() certificate1 = RTCCertificate.generateCertificate() session1 = RTCDtlsTransport(transport1, [certificate1]) receiver1 = DummyDataReceiver() session1._register_data_receiver(receiver1) certificate2 = RTCCertificate.generateCertificate() session2 = RTCDtlsTransport(transport2, [certificate2]) session2._register_data_receiver(BrokenDataReceiver()) run( asyncio.gather( session1.start(session2.getLocalParameters()), session2.start(session1.getLocalParameters()), ) ) # send encypted data run(session1._send_data(b"ping")) run(asyncio.sleep(0.1)) # shutdown run(session1.stop()) run(session2.stop())