Skip to content

Commit e0ce937

Browse files
committed
Copy dave support from serenity-rs#291
1 parent 2045ed7 commit e0ce937

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+751
-294
lines changed

Cargo.toml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ bytes = { optional = true, version = "1" }
2323
chacha20poly1305 = { optional = true, version = "0.10.1" }
2424
crypto-common = { optional = true, features = ["std"], version = "0.1" }
2525
dashmap = { optional = true, version = "6.1.0" }
26+
davey = { optional = true, version = "0.1.2" }
2627
derivative = "2"
2728
discortp = { default-features = false, features = [
2829
"discord",
@@ -50,7 +51,7 @@ serenity = { default-features = false, optional = true, git = "https://github.co
5051
"voice",
5152
"gateway",
5253
] }
53-
serenity-voice-model = { optional = true, version = "0.2" }
54+
serenity-voice-model = { optional = true, git = "https://github.com/serenity-rs/voice-model.git", branch = "next" }
5455
socket2 = { optional = true, version = "0.5" }
5556
streamcatcher = { optional = true, version = "1" }
5657
stream_lib = { default-features = false, optional = true, version = "0.5.2" }
@@ -104,6 +105,7 @@ driver = [
104105
"dep:bytes",
105106
"dep:chacha20poly1305",
106107
"dep:crypto-common",
108+
"dep:davey",
107109
"dep:discortp",
108110
"dep:flume",
109111
"dep:nohash-hasher",

benches/mixing-task.rs

Lines changed: 3 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,7 @@
11
use std::error::Error;
22

33
use criterion::{
4-
black_box,
5-
criterion_group,
6-
criterion_main,
7-
BatchSize,
8-
Bencher,
9-
BenchmarkId,
10-
Criterion,
4+
black_box, criterion_group, criterion_main, BatchSize, Bencher, BenchmarkId, Criterion,
115
};
126
use flume::{Receiver, Sender, TryRecvError};
137
use songbird::{
@@ -20,14 +14,10 @@ use songbird::{
2014
task_message::*,
2115
CryptoState,
2216
},
23-
Bitrate,
24-
DummyMixer,
25-
Listeners,
26-
MockScheduler,
17+
Bitrate, DummyMixer, Listeners, MockScheduler,
2718
},
2819
input::{cached::Compressed, codecs::*, Input, RawAdapter},
29-
tracks,
30-
Config,
20+
tracks, Config,
3121
};
3222
use std::{io::Cursor, net::UdpSocket, sync::Arc};
3323
use tokio::runtime::{Handle, Runtime};

src/config.rs

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,7 @@ use crate::driver::{Channels, DecodeMode, SampleRate};
33
#[cfg(feature = "driver")]
44
use crate::{
55
driver::{
6-
get_default_scheduler,
7-
retry::Retry,
8-
tasks::disposal::DisposalThread,
9-
CryptoMode,
10-
MixMode,
6+
get_default_scheduler, retry::Retry, tasks::disposal::DisposalThread, CryptoMode, MixMode,
117
Scheduler,
128
},
139
input::codecs::*,

src/driver/connection/error.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,12 @@ pub enum Error {
2525
CryptoModeInvalid,
2626
/// Selected crypto mode was not offered by server.
2727
CryptoModeUnavailable,
28+
/// Failed to create a DAVE key package.
29+
#[cfg(feature = "driver")]
30+
DaveCreateKeyPackageError(davey::errors::CreateKeyPackageError),
31+
/// An error occurred during initialization of the DAVE session.
32+
#[cfg(feature = "driver")]
33+
DaveInitializationError(davey::errors::InitError),
2834
/// An indicator that an endpoint URL was invalid.
2935
EndpointUrl,
3036
/// Discord failed to correctly respond to IP discovery.
@@ -100,6 +106,8 @@ impl fmt::Display for Error {
100106
Self::CryptoInvalidLength => write!(f, "server supplied key of wrong length"),
101107
Self::CryptoModeInvalid => write!(f, "server changed negotiated encryption mode"),
102108
Self::CryptoModeUnavailable => write!(f, "server did not offer chosen encryption mode"),
109+
Self::DaveCreateKeyPackageError(e) => e.fmt(f),
110+
Self::DaveInitializationError(e) => e.fmt(f),
103111
Self::EndpointUrl => write!(f, "endpoint URL received from gateway was invalid"),
104112
Self::IllegalDiscoveryResponse => {
105113
write!(f, "IP discovery/NAT punching response was invalid")
@@ -122,6 +130,8 @@ impl StdError for Error {
122130
| Error::CryptoInvalidLength
123131
| Error::CryptoModeInvalid
124132
| Error::CryptoModeUnavailable
133+
| Error::DaveCreateKeyPackageError(_)
134+
| Error::DaveInitializationError(_)
125135
| Error::EndpointUrl
126136
| Error::IllegalDiscoveryResponse
127137
| Error::IllegalIp

src/driver/connection/mod.rs

Lines changed: 63 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -8,27 +8,31 @@ use super::{
88
message::*,
99
ws::{self as ws_task, AuxNetwork},
1010
},
11-
Config,
12-
CryptoMode,
11+
Config, CryptoMode,
1312
};
1413
use crate::{
1514
constants::*,
1615
model::{
1716
payload::{Identify, Resume, SelectProtocol},
18-
Event as GatewayEvent,
19-
ProtocolData,
17+
Event as GatewayEvent, ProtocolData,
2018
},
2119
ws::WsStream,
2220
ConnectionInfo,
2321
};
2422
use discortp::discord::{IpDiscoveryPacket, IpDiscoveryType, MutableIpDiscoveryPacket};
2523
use error::{Error, Result};
2624
use flume::Sender;
25+
use serenity_voice_model::payload::DaveMlsKeyPackage;
2726
use socket2::Socket;
2827
#[cfg(feature = "receive")]
2928
use std::sync::Arc;
30-
use std::{net::IpAddr, str::FromStr};
31-
use tokio::{net::UdpSocket, spawn, time::timeout};
29+
use std::{
30+
net::IpAddr,
31+
num::NonZeroU16,
32+
str::FromStr,
33+
sync::{atomic::AtomicU16, Arc},
34+
};
35+
use tokio::{net::UdpSocket, spawn, sync::RwLock, time::timeout};
3236
use tracing::{debug, info, instrument};
3337
use url::Url;
3438

@@ -72,11 +76,12 @@ impl Connection {
7276
session_id: info.session_id.clone(),
7377
token: info.token.clone(),
7478
user_id: info.user_id.into(),
79+
max_dave_protocol_version: Some(davey::DAVE_PROTOCOL_VERSION),
7580
}))
7681
.await?;
7782

7883
loop {
79-
let Some(value) = client.recv_json().await? else {
84+
let Some(value) = client.recv_event().await? else {
8085
continue;
8186
};
8287

@@ -181,7 +186,10 @@ impl Connection {
181186
.await?;
182187
}
183188

184-
let cipher = init_cipher(&mut client, chosen_crypto, &ws_msg_tx).await?;
189+
let (cipher, dave_session, dave_protocol_version) =
190+
init_cipher(&mut client, &info, chosen_crypto, &ws_msg_tx).await?;
191+
let dave_session = Arc::new(RwLock::new(dave_session));
192+
let dave_protocol_version = Arc::new(dave_protocol_version);
185193

186194
info!("Connected to: {}", info.endpoint);
187195

@@ -213,6 +221,8 @@ impl Connection {
213221
cipher: cipher.clone(),
214222
#[cfg(not(feature = "receive"))]
215223
cipher,
224+
dave_session: dave_session.clone(),
225+
dave_protocol_version: dave_protocol_version.clone(),
216226
crypto_state: chosen_crypto.into(),
217227
#[cfg(feature = "receive")]
218228
udp_rx: udp_receiver_msg_tx,
@@ -237,6 +247,14 @@ impl Connection {
237247
hello.heartbeat_interval,
238248
idx,
239249
info.clone(),
250+
#[cfg(not(feature = "receive"))]
251+
dave_session,
252+
#[cfg(not(feature = "receive"))]
253+
dave_protocol_version,
254+
#[cfg(feature = "receive")]
255+
dave_session.clone(),
256+
#[cfg(feature = "receive")]
257+
dave_protocol_version.clone(),
240258
#[cfg(feature = "receive")]
241259
ssrc_tracker.clone(),
242260
);
@@ -252,6 +270,8 @@ impl Connection {
252270
config.clone(),
253271
udp_rx,
254272
ssrc_tracker,
273+
dave_session,
274+
dave_protocol_version,
255275
));
256276

257277
Ok(Connection {
@@ -290,7 +310,7 @@ impl Connection {
290310
let mut resumed = None;
291311

292312
loop {
293-
let Some(value) = client.recv_json().await? else {
313+
let Some(value) = client.recv_event().await? else {
294314
continue;
295315
};
296316

@@ -344,11 +364,12 @@ fn generate_url(endpoint: &mut String) -> Result<Url> {
344364
#[inline]
345365
async fn init_cipher(
346366
client: &mut WsStream,
367+
info: &ConnectionInfo,
347368
mode: CryptoMode,
348369
tx: &Sender<WsMessage>,
349-
) -> Result<Cipher> {
370+
) -> Result<(Cipher, Option<davey::DaveSession>, AtomicU16)> {
350371
loop {
351-
let Some(value) = client.recv_json().await? else {
372+
let Some(value) = client.recv_event().await? else {
352373
continue;
353374
};
354375

@@ -358,9 +379,37 @@ async fn init_cipher(
358379
return Err(Error::CryptoModeInvalid);
359380
}
360381

361-
return mode
362-
.cipher_from_key(&desc.secret_key)
363-
.map_err(|_| Error::CryptoInvalidLength);
382+
let dave_session =
383+
if let Some(version) = NonZeroU16::new(desc.dave_protocol_version) {
384+
let mut session = davey::DaveSession::new(
385+
version,
386+
info.user_id.get(),
387+
info.channel_id
388+
.expect("channel ID must be set in connection info")
389+
.get(),
390+
None,
391+
)
392+
.map_err(Error::DaveInitializationError)?;
393+
394+
client
395+
.send_binary(&GatewayEvent::DaveMlsKeyPackage(DaveMlsKeyPackage {
396+
key_package: session
397+
.create_key_package()
398+
.map_err(Error::DaveCreateKeyPackageError)?,
399+
}))
400+
.await?;
401+
402+
Some(session)
403+
} else {
404+
None
405+
};
406+
407+
return Ok((
408+
mode.cipher_from_key(&desc.secret_key)
409+
.map_err(|_| Error::CryptoInvalidLength)?,
410+
dave_session,
411+
AtomicU16::new(desc.dave_protocol_version),
412+
));
364413
},
365414
other => {
366415
// Discord can and will send user-specific payload packets during this time

src/driver/crypto.rs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -91,8 +91,9 @@ impl CryptoMode {
9191
EncryptionAlgorithm::Aes256Gcm => Aes256Gcm::new_from_slice(key)
9292
.map(Box::new)
9393
.map(Cipher::Aes256Gcm),
94-
EncryptionAlgorithm::XChaCha20Poly1305 =>
95-
XChaCha20Poly1305::new_from_slice(key).map(Cipher::XChaCha20Poly1305),
94+
EncryptionAlgorithm::XChaCha20Poly1305 => {
95+
XChaCha20Poly1305::new_from_slice(key).map(Cipher::XChaCha20Poly1305)
96+
},
9697
}
9798
}
9899

@@ -255,8 +256,9 @@ impl From<CryptoMode> for CryptoState {
255256
fn from(val: CryptoMode) -> Self {
256257
match val {
257258
CryptoMode::Aes256Gcm => CryptoState::Aes256Gcm(Wrapping(rand::random::<u32>())),
258-
CryptoMode::XChaCha20Poly1305 =>
259-
CryptoState::XChaCha20Poly1305(Wrapping(rand::random::<u32>())),
259+
CryptoMode::XChaCha20Poly1305 => {
260+
CryptoState::XChaCha20Poly1305(Wrapping(rand::random::<u32>()))
261+
},
260262
}
261263
}
262264
}

src/driver/mod.rs

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -31,12 +31,8 @@ pub(crate) use crypto::CryptoState;
3131
pub use decode_mode::*;
3232
pub use mix_mode::MixMode;
3333
pub use scheduler::{
34-
get_default_scheduler,
35-
Config as SchedulerConfig,
36-
Error as SchedulerError,
37-
LiveStatBlock,
38-
Mode as SchedulerMode,
39-
Scheduler,
34+
get_default_scheduler, Config as SchedulerConfig, Error as SchedulerError, LiveStatBlock,
35+
Mode as SchedulerMode, Scheduler,
4036
};
4137
#[cfg(test)]
4238
pub use test_config::*;
@@ -49,10 +45,7 @@ use crate::{
4945
events::EventData,
5046
input::Input,
5147
tracks::{Track, TrackHandle},
52-
Config,
53-
ConnectionInfo,
54-
Event,
55-
EventHandler,
48+
Config, ConnectionInfo, Event, EventHandler,
5649
};
5750
/// Opus encoder bitrate settings.
5851
pub use audiopus::{self as opus, Bitrate};

src/driver/tasks/error.rs

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ pub type Result<T> = std::result::Result<T, Error>;
2020
#[non_exhaustive]
2121
pub enum Error {
2222
Crypto(CryptoError),
23+
DaveEncrypt(davey::errors::EncryptError),
2324
#[cfg(any(feature = "receive", test))]
2425
/// Received an illegal voice packet on the voice UDP socket.
2526
IllegalVoicePacket,
@@ -58,6 +59,12 @@ impl From<CryptoError> for Error {
5859
}
5960
}
6061

62+
impl From<davey::errors::EncryptError> for Error {
63+
fn from(value: davey::errors::EncryptError) -> Self {
64+
Self::DaveEncrypt(value)
65+
}
66+
}
67+
6168
impl From<IoError> for Error {
6269
fn from(e: IoError) -> Error {
6370
Error::Io(e)
@@ -100,3 +107,43 @@ impl From<WsError> for Error {
100107
Error::Other
101108
}
102109
}
110+
111+
#[derive(Debug)]
112+
#[non_exhaustive]
113+
pub enum DaveReinitError {
114+
Init(davey::errors::InitError),
115+
Reinit(davey::errors::ReinitError),
116+
Reset(davey::errors::ResetError),
117+
CreateKeyPackage(davey::errors::CreateKeyPackageError),
118+
Ws(WsError),
119+
}
120+
121+
impl From<davey::errors::InitError> for DaveReinitError {
122+
fn from(value: davey::errors::InitError) -> Self {
123+
Self::Init(value)
124+
}
125+
}
126+
127+
impl From<davey::errors::ReinitError> for DaveReinitError {
128+
fn from(value: davey::errors::ReinitError) -> Self {
129+
Self::Reinit(value)
130+
}
131+
}
132+
133+
impl From<davey::errors::ResetError> for DaveReinitError {
134+
fn from(value: davey::errors::ResetError) -> Self {
135+
Self::Reset(value)
136+
}
137+
}
138+
139+
impl From<davey::errors::CreateKeyPackageError> for DaveReinitError {
140+
fn from(value: davey::errors::CreateKeyPackageError) -> Self {
141+
Self::CreateKeyPackage(value)
142+
}
143+
}
144+
145+
impl From<WsError> for DaveReinitError {
146+
fn from(value: WsError) -> Self {
147+
Self::Ws(value)
148+
}
149+
}

src/driver/tasks/message/mixer.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,18 @@ use crate::{
99
input::{AudioStreamError, Compose, Parsed},
1010
};
1111
use flume::Sender;
12-
use std::{net::UdpSocket, sync::Arc};
12+
use std::{
13+
net::UdpSocket,
14+
sync::{atomic::AtomicU16, Arc},
15+
};
1316
use symphonia_core::{errors::Error as SymphoniaError, formats::SeekedTo};
17+
use tokio::sync::RwLock;
1418

1519
pub struct MixerConnection {
1620
pub cipher: Cipher,
1721
pub crypto_state: CryptoState,
22+
pub dave_session: Arc<RwLock<Option<davey::DaveSession>>>,
23+
pub dave_protocol_version: Arc<AtomicU16>,
1824
#[cfg(feature = "receive")]
1925
pub udp_rx: Sender<UdpRxMessage>,
2026
pub udp_tx: UdpSocket,

0 commit comments

Comments
 (0)