aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGilles Henaux <gill.henaux@gmail.com>2023-02-20 21:55:35 +0100
committerGitHub <noreply@github.com>2023-02-20 21:55:35 +0100
commitb3b926fb27012bf5f975efd3cd80dab0c65bda2e (patch)
tree38a9eeee0ad07b8ee6e970b524133b116e7bb767
parent81527b24060ab73f5bdaad252a2d62fd42f36dd7 (diff)
parentc77e90c7b322b8ada71590d938150579b76431d5 (diff)
Merge pull request #14 from Henauxg/ipv6-handling
[client & server] Fix IPv6 handling
-rw-r--r--CHANGELOG.md11
-rw-r--r--README.md13
-rw-r--r--examples/breakout/breakout.rs3
-rw-r--r--examples/breakout/client.rs10
-rw-r--r--examples/breakout/server.rs20
-rw-r--r--examples/chat/client.rs2
-rw-r--r--examples/chat/server.rs8
-rw-r--r--src/client/connection.rs164
-rw-r--r--src/server.rs101
-rw-r--r--src/server/certificate.rs23
-rw-r--r--tests/certificates.rs14
-rw-r--r--tests/utils/mod.rs19
12 files changed, 266 insertions, 122 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index f8543bd..4b82593 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,16 @@
# Changelog
+## Version 0.4.0-dev
+
+- [client]: Fix IPv6 handling.
+ - Remove `ConnectionConfiguration::new`
+ - Add `ConnectionConfiguration::from_strings`, `ConnectionConfiguration::from_ips` and `ConnectionConfiguration::from_addrs`
+- [server]: Fix IPv6 handling.
+ - Rename `ServerConfigurationData` to `ServerConfiguration`.
+ - Remove `ServerConfiguration::new`
+ - Add `ServerConfiguration::from_string`, `ServerConfiguration::from_ip` and `ServerConfiguration::from_addr`
+ - Add `server_hostname` to `CertificateRetrievalMode::GenerateSelfSigned` and `CertificateRetrievalMode::LoadFromFileOrGenerateSelfSigned`
+
## Version 0.3.0 (2023-01-20)
### Added
diff --git a/README.md b/README.md
index 4e0629d..f45c515 100644
--- a/README.md
+++ b/README.md
@@ -95,10 +95,10 @@ This is a bird-eye view of the features/tasks that will probably be worked on ne
fn start_connection(client: ResMut<Client>) {
client
.open_connection(
- ClientConfigurationData::new(
- "127.0.0.1".to_string(),
+ ClientConfigurationData::from_ips(
+ IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)),
6000,
- "0.0.0.0".to_string(),
+ IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)),
0,
),
CertificateVerificationMode::SkipVerification,
@@ -143,7 +143,7 @@ fn handle_server_messages(
fn start_listening(mut server: ResMut<Server>) {
server
.start_endpoint(
- ServerConfigurationData::new("127.0.0.1".to_string(), 6000, "0.0.0.0".to_string()),
+ ServerConfigurationData::from_ip(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), 6000),
CertificateRetrievalMode::GenerateSelfSigned,
)
.unwrap();
@@ -258,7 +258,9 @@ On the server:
```rust
// To generate a new self-signed certificate on each startup
- server.start_endpoint(/*...*/, CertificateRetrievalMode::GenerateSelfSigned);
+ server.start_endpoint(/*...*/, CertificateRetrievalMode::GenerateSelfSigned {
+ server_hostname: "127.0.0.1".to_string(),
+ });
// To load a pre-existing one from files
server.start_endpoint(/*...*/, CertificateRetrievalMode::LoadFromFile {
cert_file: "./certificates.pem".into(),
@@ -269,6 +271,7 @@ On the server:
cert_file: "./certificates.pem".into(),
key_file: "./privkey.pem".into(),
save_on_disk: true, // To persist on disk if generated
+ server_hostname: "127.0.0.1".to_string(),
});
```
diff --git a/examples/breakout/breakout.rs b/examples/breakout/breakout.rs
index e57e2d7..31fcf01 100644
--- a/examples/breakout/breakout.rs
+++ b/examples/breakout/breakout.rs
@@ -1,6 +1,8 @@
//! A simplified implementation of the classic game "Breakout".
//! => Original example by Bevy, modified for Bevy Quinnet to add a 2 players versus mode.
+use std::net::{IpAddr, Ipv4Addr};
+
use bevy::{ecs::schedule::ShouldRun, prelude::*, time::FixedTimestep};
use bevy_quinnet::{
client::QuinnetClientPlugin,
@@ -13,6 +15,7 @@ mod protocol;
mod server;
const SERVER_HOST: &str = "127.0.0.1";
+const LOCAL_BIND_IP: IpAddr = IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0));
const SERVER_PORT: u16 = 6000;
// Defines the amount of time that should elapse between each physics step.
diff --git a/examples/breakout/client.rs b/examples/breakout/client.rs
index 33873d3..be4435a 100644
--- a/examples/breakout/client.rs
+++ b/examples/breakout/client.rs
@@ -24,7 +24,8 @@ use bevy_quinnet::{
use crate::{
protocol::{ClientMessage, PaddleInput, ServerMessage},
BrickId, CollisionEvent, CollisionSound, GameState, Score, Velocity, WallLocation, BALL_SIZE,
- BALL_SPEED, BRICK_SIZE, GAP_BETWEEN_BRICKS, PADDLE_SIZE, SERVER_HOST, SERVER_PORT, TIME_STEP,
+ BALL_SPEED, BRICK_SIZE, GAP_BETWEEN_BRICKS, LOCAL_BIND_IP, PADDLE_SIZE, SERVER_HOST,
+ SERVER_PORT, TIME_STEP,
};
const SCOREBOARD_FONT_SIZE: f32 = 40.0;
@@ -91,14 +92,13 @@ struct WallBundle {
#[bundle]
sprite_bundle: SpriteBundle,
}
-
pub(crate) fn start_connection(mut client: ResMut<Client>) {
client
.open_connection(
- ConnectionConfiguration::new(
- SERVER_HOST.to_string(),
+ ConnectionConfiguration::from_ips(
+ SERVER_HOST.parse().unwrap(),
SERVER_PORT,
- "0.0.0.0".to_string(),
+ LOCAL_BIND_IP,
0,
),
CertificateVerificationMode::SkipVerification,
diff --git a/examples/breakout/server.rs b/examples/breakout/server.rs
index 4164f7e..f2389bd 100644
--- a/examples/breakout/server.rs
+++ b/examples/breakout/server.rs
@@ -1,4 +1,4 @@
-use std::collections::HashMap;
+use std::{collections::HashMap};
use bevy::{
prelude::{
@@ -9,9 +9,7 @@ use bevy::{
transform::TransformBundle,
};
use bevy_quinnet::{
- server::{
- certificate::CertificateRetrievalMode, ConnectionEvent, Server, ServerConfigurationData,
- },
+ server::{certificate::CertificateRetrievalMode, ConnectionEvent, Server, ServerConfiguration},
shared::{channel::ChannelId, ClientId},
};
@@ -19,8 +17,8 @@ use crate::{
protocol::{ClientMessage, PaddleInput, ServerMessage},
BrickId, Velocity, WallLocation, BALL_SIZE, BALL_SPEED, BOTTOM_WALL, BRICK_SIZE,
GAP_BETWEEN_BRICKS, GAP_BETWEEN_BRICKS_AND_SIDES, GAP_BETWEEN_PADDLE_AND_BRICKS,
- GAP_BETWEEN_PADDLE_AND_FLOOR, LEFT_WALL, PADDLE_PADDING, PADDLE_SIZE, PADDLE_SPEED, RIGHT_WALL,
- SERVER_HOST, SERVER_PORT, TIME_STEP, TOP_WALL, WALL_THICKNESS,
+ GAP_BETWEEN_PADDLE_AND_FLOOR, LEFT_WALL, LOCAL_BIND_IP, PADDLE_PADDING, PADDLE_SIZE,
+ PADDLE_SPEED, RIGHT_WALL, SERVER_HOST, SERVER_PORT, TIME_STEP, TOP_WALL, WALL_THICKNESS,
};
const GAP_BETWEEN_PADDLE_AND_BALL: f32 = 35.;
@@ -81,12 +79,10 @@ struct WallBundle {
pub(crate) fn start_listening(mut server: ResMut<Server>) {
server
.start_endpoint(
- ServerConfigurationData::new(
- SERVER_HOST.to_string(),
- SERVER_PORT,
- "0.0.0.0".to_string(),
- ),
- CertificateRetrievalMode::GenerateSelfSigned,
+ ServerConfiguration::from_ip(LOCAL_BIND_IP, SERVER_PORT),
+ CertificateRetrievalMode::GenerateSelfSigned {
+ server_hostname: SERVER_HOST.to_string(),
+ },
)
.unwrap();
}
diff --git a/examples/chat/client.rs b/examples/chat/client.rs
index 6cb25e4..fae4976 100644
--- a/examples/chat/client.rs
+++ b/examples/chat/client.rs
@@ -120,7 +120,7 @@ fn start_terminal_listener(mut commands: Commands) {
fn start_connection(mut client: ResMut<Client>) {
client
.open_connection(
- ConnectionConfiguration::new("127.0.0.1".to_string(), 6000, "0.0.0.0".to_string(), 0),
+ ConnectionConfiguration::from_strings("127.0.0.1:6000", "0.0.0.0:0").unwrap(),
CertificateVerificationMode::SkipVerification,
)
.unwrap();
diff --git a/examples/chat/server.rs b/examples/chat/server.rs
index 8c89f2b..da28f88 100644
--- a/examples/chat/server.rs
+++ b/examples/chat/server.rs
@@ -4,7 +4,7 @@ use bevy::{app::ScheduleRunnerPlugin, log::LogPlugin, prelude::*};
use bevy_quinnet::{
server::{
certificate::CertificateRetrievalMode, ConnectionLostEvent, Endpoint, QuinnetServerPlugin,
- Server, ServerConfigurationData,
+ Server, ServerConfiguration,
},
shared::{channel::ChannelId, ClientId},
};
@@ -116,8 +116,10 @@ fn handle_disconnect(endpoint: &mut Endpoint, users: &mut ResMut<Users>, client_
fn start_listening(mut server: ResMut<Server>) {
server
.start_endpoint(
- ServerConfigurationData::new("127.0.0.1".to_string(), 6000, "0.0.0.0".to_string()),
- CertificateRetrievalMode::GenerateSelfSigned,
+ ServerConfiguration::from_string("0.0.0.0:6000").unwrap(),
+ CertificateRetrievalMode::GenerateSelfSigned {
+ server_hostname: "127.0.0.1".to_string(),
+ },
)
.unwrap();
}
diff --git a/src/client/connection.rs b/src/client/connection.rs
index f7538f6..05ab185 100644
--- a/src/client/connection.rs
+++ b/src/client/connection.rs
@@ -1,4 +1,9 @@
-use std::{collections::HashMap, error::Error, net::SocketAddr, sync::Arc};
+use std::{
+ collections::HashMap,
+ error::Error,
+ net::{AddrParseError, IpAddr, SocketAddr},
+ sync::Arc,
+};
use bevy::prelude::{error, info};
use bytes::Bytes;
@@ -45,10 +50,9 @@ pub struct ConnectionLostEvent {
/// Configuration of a client connection, used when connecting to a server
#[derive(Debug, Deserialize, Clone)]
pub struct ConnectionConfiguration {
- server_host: String,
- server_port: u16,
- local_bind_host: String,
- local_bind_port: u16,
+ server_addr: SocketAddr,
+ server_hostname: String,
+ local_bind_addr: SocketAddr,
}
impl ConnectionConfiguration {
@@ -56,33 +60,133 @@ impl ConnectionConfiguration {
///
/// # Arguments
///
- /// * `server_host` - Address of the server
- /// * `server_port` - Port that the server is listening on
- /// * `local_bind_host` - Local address to bind to, which should usually be a wildcard address like `0.0.0.0` or `[::]`, which allow communication with any reachable IPv4 or IPv6 address. See [`quinn::endpoint::Endpoint`] for more precision
- /// * `local_bind_port` - Local port to bind to. Use 0 to get an OS-assigned port.. See [`quinn::endpoint::Endpoint`] for more precision
+ /// * `server_addr_str` - IP address and port of the server
+ /// * `local_bind_addr_str` - Local address and port to bind to separated by `:`. The address should usually be a wildcard like `0.0.0.0` (for an IPv4) or `[::]` (for an IPv6), which allow communication with any reachable IPv4 or IPv6 address. See [`std::net::SocketAddrV4`] and [`std::net::SocketAddrV6`] or [`quinn::endpoint::Endpoint`] for more precision. For the local port to bind to, use 0 to get an OS-assigned port.
///
/// # Examples
///
+ /// Connect to an IPv4 server hosted on localhost (127.0.0.1), which is listening on port 6000. Use 0 as a local bind port to let the OS assign a port.
+ /// ```
+ /// use bevy_quinnet::client::connection::ConnectionConfiguration;
+ /// let config = ConnectionConfiguration::from_strings(
+ /// "127.0.0.1:6000",
+ /// "0.0.0.0:0"
+ /// );
+ /// ```
+ /// Connect to an IPv6 server hosted on localhost (::1), which is listening on port 6000. Use 0 as a local bind port to let the OS assign a port.
/// ```
/// use bevy_quinnet::client::connection::ConnectionConfiguration;
- /// let config = ConnectionConfiguration::new(
- /// "127.0.0.1".to_string(),
- /// 6000,
- /// "0.0.0.0".to_string(),
- /// 0,
- /// );
+ /// let config = ConnectionConfiguration::from_strings(
+ /// "[::1]:6000",
+ /// "[::]:0"
+ /// );
/// ```
- pub fn new(
- server_host: String,
+ pub fn from_strings(
+ server_addr_str: &str,
+ local_bind_addr_str: &str,
+ ) -> Result<Self, AddrParseError> {
+ let server_addr = server_addr_str.parse()?;
+ let local_bind_addr = local_bind_addr_str.parse()?;
+ Ok(Self::from_addrs(server_addr, local_bind_addr))
+ }
+
+ /// Same as [`ConnectionConfiguration::from_strings`], but with an additional `server_hostname` for certificate verification if it is not just the server IP.
+ pub fn from_strings_with_name(
+ server_addr_str: &str,
+ server_hostname: String,
+ local_bind_addr_str: &str,
+ ) -> Result<Self, AddrParseError> {
+ Ok(Self::from_addrs_with_name(
+ server_addr_str.parse()?,
+ server_hostname,
+ local_bind_addr_str.parse()?,
+ ))
+ }
+
+ /// Creates a new ConnectionConfiguration
+ ///
+ /// # Arguments
+ ///
+ /// * `server_ip` - IP address of the server
+ /// * `server_port` - Port of the server
+ /// * `local_bind_ip` - Local IP address to bind to. The address should usually be a wildcard like `0.0.0.0` (for an IPv4) or `0:0:0:0:0:0:0:0` (for an IPv6), which allow communication with any reachable IPv4 or IPv6 address. See [`std::net::Ipv4Addr`] and [`std::net::Ipv6Addr`] for more precision.
+ /// * `local_bind_port` - Local port to bind to. Use 0 to get an OS-assigned port.
+ ///
+ /// # Examples
+ ///
+ /// Connect to an IPv4 server hosted on localhost (127.0.0.1), which is listening on port 6000. Use 0 as a local bind port to let the OS assign a port.
+ /// ```
+ /// use bevy_quinnet::client::connection::ConnectionConfiguration;
+ /// let config = ConnectionConfiguration::from_ips(
+ /// IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)),
+ /// 6000,
+ /// IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)),
+ /// 0
+ /// );
+ /// ```
+ pub fn from_ips(
+ server_ip: IpAddr,
+ server_port: u16,
+ local_bind_ip: IpAddr,
+ local_bind_port: u16,
+ ) -> Self {
+ Self::from_addrs(
+ SocketAddr::new(server_ip, server_port),
+ SocketAddr::new(local_bind_ip, local_bind_port),
+ )
+ }
+
+ /// Same as [`ConnectionConfiguration::from_ips`], but with an additional `server_hostname` for certificate verification if it is not just the server IP.
+ pub fn from_ips_with_name(
+ server_ip: IpAddr,
server_port: u16,
- local_bind_host: String,
+ server_hostname: String,
+ local_bind_ip: IpAddr,
local_bind_port: u16,
) -> Self {
+ Self::from_addrs_with_name(
+ SocketAddr::new(server_ip, server_port),
+ server_hostname,
+ SocketAddr::new(local_bind_ip, local_bind_port),
+ )
+ }
+
+ /// Creates a new ConnectionConfiguration
+ ///
+ /// # Arguments
+ ///
+ /// * `server_addr` - IP address and port of the server
+ /// * `local_bind_addr` - Local address and port to bind to. For the local port to bind to, use 0 to get an OS-assigned port.
+ ///
+ /// # Examples
+ ///
+ /// Connect to an IPv4 server hosted on localhost (127.0.0.1), which is listening on port 6000. Use 0 as a local bind port to let the OS assign a port.
+ /// ```
+ /// use bevy_quinnet::client::connection::ConnectionConfiguration;
+ /// use std::{net::{IpAddr, Ipv4Addr, SocketAddr}};
+ /// let config = ConnectionConfiguration::from_addrs(
+ /// SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 6000),
+ /// SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), 0),
+ /// );
+ /// ```
+ pub fn from_addrs(server_addr: SocketAddr, local_bind_addr: SocketAddr) -> Self {
+ Self {
+ server_addr,
+ server_hostname: server_addr.ip().to_string(),
+ local_bind_addr,
+ }
+ }
+
+ /// Same as [`ConnectionConfiguration::from_addrs`], but with an additional `server_hostname` for certificate verification if it is not just the server IP.
+ pub fn from_addrs_with_name(
+ server_addr: SocketAddr,
+ server_hostname: String,
+ local_bind_addr: SocketAddr,
+ ) -> Self {
Self {
- server_host,
- server_port,
- local_bind_host,
- local_bind_port,
+ server_addr,
+ server_hostname,
+ local_bind_addr,
}
}
}
@@ -380,28 +484,20 @@ pub(crate) async fn connection_task(
close_recv: broadcast::Receiver<()>,
bytes_from_server_send: mpsc::Sender<Bytes>,
) {
- let server_adr_str = format!("{}:{}", config.server_host, config.server_port);
- let srv_host = config.server_host.clone();
- let local_bind_adr = format!("{}:{}", config.local_bind_host, config.local_bind_port);
-
info!(
"Connection {} trying to connect to server on: {} ...",
- connection_id, server_adr_str
+ connection_id, config.server_addr
);
- let server_addr: SocketAddr = server_adr_str
- .parse()
- .expect("Failed to parse server address");
-
let client_cfg = configure_client(cert_mode, to_sync_client_send.clone())
.expect("Failed to configure client");
- let mut endpoint = Endpoint::client(local_bind_adr.parse().unwrap())
- .expect("Failed to create client endpoint");
+ let mut endpoint =
+ Endpoint::client(config.local_bind_addr).expect("Failed to create client endpoint");
endpoint.set_default_client_config(client_cfg);
let connection = endpoint
- .connect(server_addr, &srv_host) // TODO Clean: error handling
+ .connect(config.server_addr, &config.server_hostname)
.expect("Failed to connect: configuration error")
.await;
match connection {
diff --git a/src/server.rs b/src/server.rs
index c2ab409..ae3bd82 100644
--- a/src/server.rs
+++ b/src/server.rs
@@ -1,6 +1,6 @@
use std::{
collections::{HashMap, HashSet},
- net::SocketAddr,
+ net::{AddrParseError, IpAddr, SocketAddr},
sync::Arc,
time::Duration,
};
@@ -52,50 +52,76 @@ pub struct ConnectionLostEvent {
pub id: ClientId,
}
-/// Configuration of the server, used when the server starts
-///
-/// # Examples
-///
-/// ```
-/// use bevy_quinnet::server::ServerConfigurationData;
-/// let config = ServerConfigurationData::new(
-/// "127.0.0.1".to_string(),
-/// 6000,
-/// "0.0.0.0".to_string());
-/// ```
+/// Configuration of the server, used when the server starts an Endpoint
#[derive(Debug, Deserialize, Clone)]
-pub struct ServerConfigurationData {
- host: String,
- port: u16,
- local_bind_host: String,
+pub struct ServerConfiguration {
+ local_bind_addr: SocketAddr,
}
-impl ServerConfigurationData {
- /// Creates a new ServerConfigurationData
+impl ServerConfiguration {
+ /// Creates a new ServerConfiguration
///
/// # Arguments
///
- /// * `host` - Address of the server
- /// * `port` - Port that the server is listening on
- /// * `local_bind_host` - Local address to bind to, which should usually be a wildcard address like `0.0.0.0` or `[::]`, which allow communication with any reachable IPv4 or IPv6 address. See [`quinn::endpoint::Endpoint`] for more precision
+ /// * `local_bind_addr_str` - Local address and port to bind to separated by `:`. The address should usually be a wildcard like `0.0.0.0` (for an IPv4) or `[::]` (for an IPv6), which allow communication with any reachable IPv4 or IPv6 address. See [`std::net::SocketAddrV4`] and [`std::net::SocketAddrV6`] or [`quinn::endpoint::Endpoint`] for more precision.
///
/// # Examples
///
+ /// Listen on port 6000, on an IPv4 endpoint, for all incoming IPs.
/// ```
- /// use bevy_quinnet::server::ServerConfigurationData;
- /// let config = ServerConfigurationData::new(
- /// "127.0.0.1".to_string(),
- /// 6000,
- /// "0.0.0.0".to_string(),
- /// );
+ /// use bevy_quinnet::server::ServerConfiguration;
+ /// let config = ServerConfiguration::from_string("0.0.0.0:6000");
/// ```
- pub fn new(host: String, port: u16, local_bind_host: String) -> Self {
+ /// Listen on port 6000, on an IPv6 endpoint, for all incoming IPs.
+ /// ```
+ /// use bevy_quinnet::server::ServerConfiguration;
+ /// let config = ServerConfiguration::from_string("[::]:6000");
+ /// ```
+ pub fn from_string(local_bind_addr_str: &str) -> Result<Self, AddrParseError> {
+ let local_bind_addr = local_bind_addr_str.parse()?;
+ Ok(Self { local_bind_addr })
+ }
+
+ /// Creates a new ServerConfiguration
+ ///
+ /// # Arguments
+ ///
+ /// * `local_bind_ip` - Local IP address to bind to. The address should usually be a wildcard like `0.0.0.0` (for an IPv4) or `0:0:0:0:0:0:0:0` (for an IPv6), which allow communication with any reachable IPv4 or IPv6 address. See [`std::net::Ipv4Addr`] and [`std::net::Ipv6Addr`] for more precision.
+ /// * `local_bind_port` - Local port to bind to.
+ ///
+ /// # Examples
+ ///
+ /// Listen on port 6000, on an IPv4 endpoint, for all incoming IPs.
+ /// ```
+ /// use bevy_quinnet::server::ServerConfiguration;
+ /// let config = ServerConfiguration::from_ip(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), 6000);
+ /// ```
+ pub fn from_ip(local_bind_ip: IpAddr, local_bind_port: u16) -> Self {
Self {
- host,
- port,
- local_bind_host,
+ local_bind_addr: SocketAddr::new(local_bind_ip, local_bind_port),
}
}
+
+ /// Creates a new ServerConfiguration
+ ///
+ /// # Arguments
+ ///
+ /// * `local_bind_addr` - Local address and port to bind to.
+ /// See [`std::net::SocketAddrV4`] and [`std::net::SocketAddrV6`] for more precision.
+ ///
+ /// # Examples
+ ///
+ /// Listen on port 6000, on an IPv4 endpoint, for all incoming IPs.
+ /// ```
+ /// use bevy_quinnet::server::ServerConfiguration;
+ /// use std::{net::{IpAddr, Ipv4Addr, SocketAddr}};
+ /// let config = ServerConfiguration::from_addr(
+ /// SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), 6000),
+ /// );
+ /// ```
+ pub fn from_addr(local_bind_addr: SocketAddr) -> Self {
+ Self { local_bind_addr }
+ }
}
#[derive(Debug)]
@@ -635,19 +661,16 @@ impl Server {
self.endpoint.as_mut()
}
- /// Starts a new endpoint with the given [ServerConfigurationData] and [CertificateRetrievalMode] and opens the default channels.
+ /// Starts a new endpoint with the given [ServerConfiguration] and [CertificateRetrievalMode] and opens the default channels.
///
/// Returns a tuple of the [ServerCertificate] generated or loaded, and the default [ChannelId]
pub fn start_endpoint(
&mut self,
- config: ServerConfigurationData,
+ config: ServerConfiguration,
cert_mode: CertificateRetrievalMode,
) -> Result<(ServerCertificate, ChannelId), QuinnetError> {
- let server_adr_str = format!("{}:{}", config.local_bind_host, config.port);
- let server_addr = server_adr_str.parse::<SocketAddr>()?;
-
// Endpoint configuration
- let server_cert = retrieve_certificate(&config.host, cert_mode)?;
+ let server_cert = retrieve_certificate(cert_mode)?;
let mut server_config = ServerConfig::with_single_cert(
server_cert.cert_chain.clone(),
server_cert.priv_key.clone(),
@@ -661,12 +684,12 @@ impl Server {
let (endpoint_close_send, endpoint_close_recv) =
broadcast::channel(DEFAULT_KILL_MESSAGE_QUEUE_SIZE);
- info!("Starting endpoint on: {} ...", server_adr_str);
+ info!("Starting endpoint on: {} ...", config.local_bind_addr);
self.runtime.spawn(async move {
endpoint_task(
server_config,
- server_addr,
+ config.local_bind_addr,
to_sync_server_send.clone(),
endpoint_close_recv,
)
diff --git a/src/server/certificate.rs b/src/server/certificate.rs
index f13ce16..00bbad3 100644
--- a/src/server/certificate.rs
+++ b/src/server/certificate.rs
@@ -11,8 +11,8 @@ use crate::shared::{CertificateFingerprint, QuinnetError};
/// Represents the origin of a certificate.
#[derive(Debug, Clone)]
pub enum CertOrigin {
- /// Indicates that the certificate was generated. The `server_host` field contains the hostname used when generating the certificate.
- Generated { server_host: String },
+ /// Indicates that the certificate was generated. The `server_hostname` field contains the hostname used when generating the certificate.
+ Generated { server_hostname: String },
/// Indicates that the certificate was loaded from a file.
Loaded,
}
@@ -20,16 +20,17 @@ pub enum CertOrigin {
/// How the server should retrieve its certificate.
#[derive(Debug, Clone)]
pub enum CertificateRetrievalMode {
- /// The server will always generate a new self-signed certificate when starting up
- GenerateSelfSigned,
- /// Try to load cert & key from files.
+ /// The server will always generate a new self-signed certificate when starting up, using `server_hostname` as the subject of the certificate.
+ GenerateSelfSigned { server_hostname: String },
+ /// Try to load cert & key from files `cert_file``and `key_file`.
LoadFromFile { cert_file: String, key_file: String },
- /// Try to load cert & key from files.
- /// If the files do not exist, generate a self-signed certificate, and optionally save it to disk.
+ /// Try to load cert & key from files `cert_file``and `key_file`.
+ /// If the files do not exist, generate a self-signed certificate using `server_hostname` as the subject of the certificate. Optionally save it to disk if `save_on_disk` is enabled.
LoadFromFileOrGenerateSelfSigned {
cert_file: String,
key_file: String,
save_on_disk: bool,
+ server_hostname: String,
},
}
@@ -111,12 +112,11 @@ fn generate_self_signed_certificate(
}
pub(crate) fn retrieve_certificate(
- server_host: &String,
cert_mode: CertificateRetrievalMode,
) -> Result<ServerCertificate, QuinnetError> {
match cert_mode {
- CertificateRetrievalMode::GenerateSelfSigned => {
- let (server_cert, _rcgen_cert) = generate_self_signed_certificate(server_host)?;
+ CertificateRetrievalMode::GenerateSelfSigned { server_hostname } => {
+ let (server_cert, _rcgen_cert) = generate_self_signed_certificate(&server_hostname)?;
trace!("Generatied a new self-signed certificate");
Ok(server_cert)
}
@@ -132,6 +132,7 @@ pub(crate) fn retrieve_certificate(
save_on_disk,
cert_file,
key_file,
+ server_hostname,
} => {
if Path::new(&cert_file).exists() && Path::new(&key_file).exists() {
let server_cert = read_certs_from_files(&cert_file, &key_file)?;
@@ -139,7 +140,7 @@ pub(crate) fn retrieve_certificate(
Ok(server_cert)
} else {
warn!("{} and/or {} do not exist, could not load existing certificate. Generating a new self-signed certificate.", cert_file, key_file);
- let (server_cert, rcgen_cert) = generate_self_signed_certificate(server_host)?;
+ let (server_cert, rcgen_cert) = generate_self_signed_certificate(&server_hostname)?;
if save_on_disk {
write_certs_to_files(&rcgen_cert, &cert_file, &key_file)?;
trace!("Successfuly saved cert and key to files");
diff --git a/tests/certificates.rs b/tests/certificates.rs
index 21daec7..1745b0d 100644
--- a/tests/certificates.rs
+++ b/tests/certificates.rs
@@ -8,7 +8,7 @@ use bevy_quinnet::{
Client, QuinnetClientPlugin, DEFAULT_KNOWN_HOSTS_FILE,
},
server::{
- certificate::CertificateRetrievalMode, QuinnetServerPlugin, Server, ServerConfigurationData,
+ certificate::CertificateRetrievalMode, QuinnetServerPlugin, Server, ServerConfiguration,
},
};
@@ -72,7 +72,7 @@ fn trust_on_first_use() {
let mut server = server_app.world.resource_mut::<Server>();
let (server_cert, _) = server
.start_endpoint(
- ServerConfigurationData::new(SERVER_HOST.to_string(), port, "0.0.0.0".to_string()),
+ ServerConfiguration::from_ip("0.0.0.0".parse().unwrap(), port),
CertificateRetrievalMode::LoadFromFile {
cert_file: TEST_CERT_FILE.to_string(),
key_file: TEST_KEY_FILE.to_string(),
@@ -130,7 +130,7 @@ fn trust_on_first_use() {
);
assert_eq!(
cert_info.server_name.to_string(),
- SERVER_HOST.to_string(),
+ SERVER_IP.to_string(),
"The server name should match the one we configured"
);
@@ -200,8 +200,10 @@ fn trust_on_first_use() {
.world
.resource_mut::<Server>()
.start_endpoint(
- ServerConfigurationData::new(SERVER_HOST.to_string(), port, "0.0.0.0".to_string()),
- CertificateRetrievalMode::GenerateSelfSigned,
+ ServerConfiguration::from_ip(LOCAL_BIND_IP, port),
+ CertificateRetrievalMode::GenerateSelfSigned {
+ server_hostname: SERVER_IP.to_string(),
+ },
)
.unwrap();
@@ -270,7 +272,7 @@ fn trust_on_first_use() {
);
assert_eq!(
interaction_cert_info.server_name.to_string(),
- SERVER_HOST.to_string(),
+ SERVER_IP.to_string(),
"The server name in the certificate interaction event should be the server we want to connect to"
);
assert_eq!(
diff --git a/tests/utils/mod.rs b/tests/utils/mod.rs
index 24b0ac8..55a1353 100644
--- a/tests/utils/mod.rs
+++ b/tests/utils/mod.rs
@@ -1,4 +1,8 @@
-use std::{thread::sleep, time::Duration};
+use std::{
+ net::{IpAddr, Ipv4Addr},
+ thread::sleep,
+ time::Duration,
+};
use bevy::{
app::ScheduleRunnerPlugin,
@@ -17,7 +21,7 @@ use bevy_quinnet::{
},
server::{
self, certificate::CertificateRetrievalMode, QuinnetServerPlugin, Server,
- ServerConfigurationData,
+ ServerConfiguration,
},
shared::{
channel::{ChannelId, ChannelType},
@@ -56,7 +60,8 @@ pub enum SharedMessage {
TestMessage(String),
}
-pub const SERVER_HOST: &str = "127.0.0.1";
+pub const SERVER_IP: IpAddr = IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1));
+pub const LOCAL_BIND_IP: IpAddr = IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0));
pub fn build_client_app() -> App {
let mut client_app = App::new();
@@ -81,7 +86,7 @@ pub fn build_server_app() -> App {
}
pub fn default_client_configuration(port: u16) -> ConnectionConfiguration {
- ConnectionConfiguration::new(SERVER_HOST.to_string(), port, "0.0.0.0".to_string(), 0)
+ ConnectionConfiguration::from_ips(SERVER_IP, port, LOCAL_BIND_IP, 0)
}
pub fn start_simple_connection(mut client: ResMut<Client>, port: Res<Port>) {
@@ -96,8 +101,10 @@ pub fn start_simple_connection(mut client: ResMut<Client>, port: Res<Port>) {
pub fn start_listening(mut server: ResMut<Server>, port: Res<Port>) {
server
.start_endpoint(
- ServerConfigurationData::new(SERVER_HOST.to_string(), port.0, "0.0.0.0".to_string()),
- CertificateRetrievalMode::GenerateSelfSigned,
+ ServerConfiguration::from_ip(LOCAL_BIND_IP, port.0),
+ CertificateRetrievalMode::GenerateSelfSigned {
+ server_hostname: SERVER_IP.to_string(),
+ },
)
.unwrap();
}