diff --git a/kissmp-bridge/Cargo.toml b/kissmp-bridge/Cargo.toml index fe9f971..b603dff 100644 --- a/kissmp-bridge/Cargo.toml +++ b/kissmp-bridge/Cargo.toml @@ -14,21 +14,19 @@ kissmp-server = { path = "../kissmp-server" } bincode = "1.3" serde = { version = "1.0", features = ["derive"] } serde_json="1.0" -futures = "0.3.5" -quinn = "0.7.1" -# Held back due to rustls using webpki 0.21 -webpki = "0.21" -anyhow = "1.0.32" +futures = "0.3" +quinn = "0.8" +anyhow = "1.0" reqwest = { version = "0.11", default-features = false, features=["rustls-tls"] } -tiny_http="0.8" +tiny_http="0.11" tokio-stream="0.1.5" -rustls = { version = "0.19", features = ["dangerous_configuration"] } +rustls = { version = "0.20", features = ["dangerous_configuration"] } tokio = { version = "1.4", features = ["time", "macros", "sync", "io-util", "net"] } discord-rpc-client = {version = "0.3", optional = true} percent-encoding = "2.1" audiopus = "0.2" -rodio = "0.14" +rodio = "0.15" cpal = "0.13" -fon = "0.5.0" +fon = "0.6" log = "0.4" -indoc = "1.0" \ No newline at end of file +indoc = "1.0" diff --git a/kissmp-bridge/src/main.rs b/kissmp-bridge/src/main.rs index 880608d..5c3d93a 100644 --- a/kissmp-bridge/src/main.rs +++ b/kissmp-bridge/src/main.rs @@ -4,6 +4,7 @@ pub mod voice_chat; use futures::stream::FuturesUnordered; use futures::{StreamExt}; +use std::convert::TryInto; use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, ToSocketAddrs}; use tokio::io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt, WriteHalf}; use tokio::net::{TcpListener, TcpStream}; @@ -86,39 +87,39 @@ async fn main() { } } +fn build_quinn_client_config() -> quinn::ClientConfig { + use std::sync::Arc; + + let client_crypto_config = rustls::ClientConfig::builder() + .with_safe_defaults() + .with_custom_certificate_verifier(Arc::new(AcceptAnyCertificate)) + .with_no_client_auth(); + + let mut c = quinn::ClientConfig::new(Arc::new(client_crypto_config)); + Arc::get_mut(&mut c.transport) + .unwrap() + .max_idle_timeout(Some(SERVER_IDLE_TIMEOUT.try_into().unwrap())); + + c +} + async fn connect_to_server( addr: SocketAddr, client_stream: TcpStream, discord_tx: std::sync::mpsc::Sender ) -> () { let endpoint = { - let mut client_cfg = quinn::ClientConfig::default(); - - let mut transport = quinn::TransportConfig::default(); - transport - .max_idle_timeout(Some(SERVER_IDLE_TIMEOUT)) - .unwrap(); - client_cfg.transport = std::sync::Arc::new(transport); - - let tls_cfg = std::sync::Arc::get_mut(&mut client_cfg.crypto).unwrap(); - tls_cfg - .dangerous() - .set_certificate_verifier(std::sync::Arc::new(AcceptAnyCertificate)); - - let mut endpoint = quinn::Endpoint::builder(); - endpoint.default_client_config(client_cfg); - - let bind_from = match addr { - SocketAddr::V4(_) => IpAddr::from(Ipv4Addr::UNSPECIFIED), - SocketAddr::V6(_) => IpAddr::from(Ipv6Addr::UNSPECIFIED), - }; + let mut endpoint = quinn::Endpoint::client(match addr { + SocketAddr::V4(_) => SocketAddr::new(IpAddr::from(Ipv4Addr::UNSPECIFIED), 0), + SocketAddr::V6(_) => SocketAddr::new(IpAddr::from(Ipv6Addr::UNSPECIFIED), 0), + }).unwrap(); + + endpoint.set_default_client_config(build_quinn_client_config()); endpoint - .bind(&SocketAddr::new(bind_from, 0)) - .unwrap().0 }; - let server_connection = match endpoint.connect(&addr, "kissmp").unwrap().await { + let server_connection = match endpoint.connect(addr, "kissmp").unwrap().await { Ok(c) => c, Err(e) => { error!("Failed to connect to the server: {}", e); @@ -240,7 +241,7 @@ async fn client_outgoing( async fn server_incoming( server_commands_sender: tokio::sync::mpsc::Sender, vc_playback_sender: std::sync::mpsc::Sender, - server_connection: quinn::generic::NewConnection + server_connection: quinn::NewConnection ) -> AHResult { let mut reliable_commands = server_connection .uni_streams @@ -281,7 +282,7 @@ async fn server_incoming( } async fn client_incoming( - server_stream: quinn::generic::Connection, + server_stream: quinn::Connection, vc_playback_sender: std::sync::mpsc::Sender, mut client_stream_reader: tokio::io::ReadHalf, vc_recording_sender: std::sync::mpsc::Sender, @@ -325,7 +326,7 @@ async fn client_incoming( } async fn server_outgoing( - server_stream: quinn::generic::Connection, + server_stream: quinn::Connection, mut client_event_receiver: tokio::sync::mpsc::UnboundedReceiver<(bool, shared::ClientCommand)> ) -> AHResult { while let Some((reliable, client_command)) = client_event_receiver.recv().await { @@ -342,14 +343,16 @@ async fn server_outgoing( struct AcceptAnyCertificate; -impl rustls::ServerCertVerifier for AcceptAnyCertificate { +impl rustls::client::ServerCertVerifier for AcceptAnyCertificate { fn verify_server_cert( &self, - _roots: &rustls::RootCertStore, - _presented_certs: &[rustls::Certificate], - _dns_name: webpki::DNSNameRef, + _end_entity: &rustls::Certificate, + _intermediates: &[rustls::Certificate], + _server_name: &rustls::ServerName, + _scts: &mut dyn Iterator, _ocsp_response: &[u8], - ) -> Result { - Ok(rustls::ServerCertVerified::assertion()) + _now: std::time::SystemTime, + ) -> Result { + Ok(rustls::client::ServerCertVerified::assertion()) } } diff --git a/kissmp-bridge/src/voice_chat.rs b/kissmp-bridge/src/voice_chat.rs index f19b7a3..966f9a6 100644 --- a/kissmp-bridge/src/voice_chat.rs +++ b/kissmp-bridge/src/voice_chat.rs @@ -228,8 +228,8 @@ pub fn encode_and_send_samples( .map(|x| x[0]) .collect(); if sample_rate.0 != SAMPLE_RATE.0 { - let audio = fon::Audio::::with_i16_buffer(sample_rate.0, data); - let mut audio = fon::Audio::::with_stream(SAMPLE_RATE.0, &audio); + let audio = fon::Audio::::with_i16_buffer(sample_rate.0, data); + let mut audio = fon::Audio::::with_audio(SAMPLE_RATE.0, &audio); audio.as_i16_slice().to_vec() } else { data diff --git a/kissmp-master/Cargo.toml b/kissmp-master/Cargo.toml index 4c0d511..59dd197 100644 --- a/kissmp-master/Cargo.toml +++ b/kissmp-master/Cargo.toml @@ -9,9 +9,9 @@ edition = "2018" [dependencies] shared = { path = "../shared" } #tide = "0.15.0" -warp = "0.2" +warp = "0.3" serde_json="1.0" -censor = "0.1.1" -tokio={version = "0.2", features = ["rt-threaded", "macros", "net"]} +censor = "0.2" +tokio={version = "1.20", features = ["rt", "rt-multi-thread", "macros", "net"]} #async-std = { version = "1.8.0", features = ["attributes"] } serde = { version = "1.0", features = ["derive"] } diff --git a/kissmp-server/Cargo.toml b/kissmp-server/Cargo.toml index 6ed83ab..f75071e 100644 --- a/kissmp-server/Cargo.toml +++ b/kissmp-server/Cargo.toml @@ -8,28 +8,28 @@ edition = "2018" [dependencies] shared = { path = "../shared" } -rand = "0.7.3" +rand = "0.8" serde_json="1.0" -bincode="1.3.1" -rmp="0.8.9" -rmp-serde="0.14.4" -futures = "0.3.13" -quinn = "0.7.1" -anyhow = "1.0.32" -rlua = "0.17.0" -notify = "4.0.15" -tokio-util = {version = "0.6.5", features = ["codec"]} +bincode="1.3" +rmp="0.8" +rmp-serde="1.1" +futures = "0.3" +quinn = "0.8" +rustls = "0.20" +anyhow = "1.0" +rlua = "0.19" +notify = "4.0" +tokio-util = {version = "0.7", features = ["codec"]} serde = { version = "1.0", features = ["derive"] } -reqwest = { version = "0.11.2", default-features = false, features=["rustls-tls"] } -rcgen = { version = "0.8.2", default-features = false } +reqwest = { version = "0.11", default-features = false, features=["rustls-tls"] } +rcgen = { version = "0.9", default-features = false } tokio = { version = "1.4", features = ["rt-multi-thread", "time", "macros", "sync", "io-util", "io-std", "fs"] } -tokio-stream = "0.1.5" -dirs = "3.0" +tokio-stream = "0.1" +dirs = "4.0" igd = { git = "https://github.com/stevefan1999-personal/rust-igd.git", rev = "c2d1f83" } -ifcfg = "0.1.2" +ifcfg = "0.1" async-ctrlc = "1.2" -ipnetwork = "0.18" log = "0.4" [target.'cfg(unix)'.dependencies] -steamlocate = "1.0" \ No newline at end of file +steamlocate = "1.0" diff --git a/kissmp-server/src/file_transfer.rs b/kissmp-server/src/file_transfer.rs index dd3d2d3..4ca7a9e 100644 --- a/kissmp-server/src/file_transfer.rs +++ b/kissmp-server/src/file_transfer.rs @@ -31,7 +31,7 @@ pub async fn transfer_file( .unwrap(), ) .await?; - stream.finish(); + stream.finish().await; chunk_n += 1; } Ok(()) diff --git a/kissmp-server/src/lib.rs b/kissmp-server/src/lib.rs index 8ee6af4..22af2f2 100644 --- a/kissmp-server/src/lib.rs +++ b/kissmp-server/src/lib.rs @@ -1,6 +1,5 @@ #[recursion_limit = "1024"] -use ipnetwork::Ipv4Network; use shared::vehicle; pub mod config; @@ -19,13 +18,14 @@ use vehicle::*; use anyhow::{Error, Context}; use futures::FutureExt; use futures::{select, StreamExt, TryStreamExt}; -use quinn::{Certificate, CertificateChain, PrivateKey}; use std::collections::HashMap; +use std::convert::TryInto; use std::net::{IpAddr, Ipv4Addr, SocketAddr, UdpSocket}; use std::time::Duration; use tokio::sync::mpsc; use tokio_stream::wrappers::{IntervalStream, ReceiverStream}; use log::{info, warn, error}; +const CLIENT_IDLE_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(60); #[derive(Clone)] pub struct Connection { @@ -88,6 +88,26 @@ pub struct Server { tick: u64, } +fn build_quinn_server_config( + certificate_chain: Vec, + private_key: rustls::PrivateKey +) -> quinn::ServerConfig { + use std::sync::Arc; + + let server_crypto_config = rustls::ServerConfig::builder() + .with_safe_defaults() + .with_no_client_auth() + .with_single_cert(certificate_chain, private_key) + .expect("bad certificate/key for server"); + + let mut c = quinn::ServerConfig::with_crypto(Arc::new(server_crypto_config)); + Arc::get_mut(&mut c.transport) + .unwrap() + .max_idle_timeout(Some(CLIENT_IDLE_TIMEOUT.try_into().unwrap())); + + c +} + impl Server { pub fn from_config(config: config::Config) -> Self { let (lua, receiver) = lua::setup_lua(); @@ -152,29 +172,24 @@ impl Server { warn!("uPnP mapping failed."); } } - let socket = UdpSocket::bind(&addr).unwrap(); let mut ticks = IntervalStream::new(tokio::time::interval( std::time::Duration::from_secs(1) / self.tickrate as u32, )) .fuse(); + let mut send_info_ticks = IntervalStream::new(tokio::time::interval(std::time::Duration::from_secs(5))).fuse(); let (certificate_chain, key) = generate_certificate(); - let mut server_config = quinn::ServerConfigBuilder::default(); - server_config.certificate(certificate_chain, key).unwrap(); - let mut server_config = server_config.build(); + let server_config = build_quinn_server_config(certificate_chain, key); - let mut transport = quinn::TransportConfig::default(); - transport - .max_idle_timeout(Some(std::time::Duration::from_secs(60))) - .unwrap(); - server_config.transport = std::sync::Arc::new(transport); + // TODO: multiple binds (for IPv4/6 configurations, or servers with multiple interfaces) - let mut endpoint = quinn::Endpoint::builder(); - endpoint.listen(server_config); - let (_, incoming) = endpoint.with_socket(socket).unwrap(); + let (_, incoming) = quinn::Endpoint::server( + server_config, + addr + ).unwrap(); let (client_events_tx, client_events_rx) = mpsc::channel(128); let mut client_events_rx = ReceiverStream::new(client_events_rx).fuse(); @@ -431,7 +446,7 @@ impl Server { async fn drive_receive( id: u32, streams: quinn::IncomingUniStreams, - datagrams: quinn::generic::Datagrams, + datagrams: quinn::Datagrams, mut client_events_tx: mpsc::Sender<(u32, IncomingEvent)>, ) -> anyhow::Result<()> { let mut cmds = streams @@ -527,14 +542,15 @@ impl Drop for Server { } } -fn generate_certificate() -> (CertificateChain, PrivateKey) { +fn generate_certificate() -> (Vec, rustls::PrivateKey) { info!("Generating certificate..."); - let cert = rcgen::generate_simple_self_signed(vec!["kissmp".into()]).unwrap(); - let key = cert.serialize_private_key_der(); - let cert = cert.serialize_der().unwrap(); + let self_signed_certificate = rcgen::generate_simple_self_signed(vec!["kissmp".into()]).unwrap(); + let certificate = rustls::Certificate(self_signed_certificate.serialize_der().unwrap()); + let private_key = rustls::PrivateKey(self_signed_certificate.serialize_private_key_der()); + let cert_chain = vec![certificate]; ( - CertificateChain::from_certs(Certificate::from_der(&cert)), - PrivateKey::from_der(&key).unwrap(), + cert_chain, + private_key, ) } diff --git a/shared/Cargo.toml b/shared/Cargo.toml index cb81c85..0479f4d 100644 --- a/shared/Cargo.toml +++ b/shared/Cargo.toml @@ -9,9 +9,9 @@ edition = "2018" [dependencies] anyhow="1.0" serde_json="1.0" -bincode="1.3.1" -rmp="0.8.9" -rmp-serde="0.14.4" +bincode="1.3" +rmp="0.8" +rmp-serde="1.1" serde = { version = "1.0", features = ["derive"] } pretty_env_logger = "0.4" chrono = "0.4"