Skip to content

Commit

Permalink
refactor!: Separate ConfigError from Error
Browse files Browse the repository at this point in the history
Currently, the only configuration-time errors are related to certificate
generation. Since we currently generate self-signed certificates, the
only failures that could happen would be due to bugs. As such, the
`ConfigError::CertificateGeneration` variant doesn't attempt to capture
all the info, rather just an opaque `Error` (though the backtrace and
source chain will be preserved).

This removes a number of variants from `Error`.

BREAKING CHANGE: There are several breaking changes:

- `QuicP2p::from_config` now returns `Result<Self, ConfigError>`.
- The `Error::CertificateParse` variant has been removed.
- The `Error::CertificatePkParse` variant has been removed.
- The `Error::CertificateGen` variant has been removed.
- The `Error::Tls` variant has been removed.
  • Loading branch information
Chris Connelly authored and connec committed Aug 27, 2021
1 parent 4bbcd29 commit e837aca
Show file tree
Hide file tree
Showing 5 changed files with 58 additions and 30 deletions.
20 changes: 10 additions & 10 deletions src/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
// Software.

use super::{
config::{Config, InternalConfig},
config::{Config, ConfigError, InternalConfig},
connection_pool::ConnId,
connections::DisconnectionEvents,
endpoint::{Endpoint, IncomingConnections, IncomingMessages},
Expand Down Expand Up @@ -48,7 +48,7 @@ impl<I: ConnId> QuicP2p<I> {
/// let quic_p2p = QuicP2p::<XId>::with_config(Config::default())
/// .expect("Error initializing QuicP2p");
/// ```
pub fn with_config(cfg: Config) -> Result<Self> {
pub fn with_config(cfg: Config) -> Result<Self, ConfigError> {
debug!("Config passed in to qp2p: {:?}", cfg);

Ok(Self {
Expand All @@ -65,20 +65,20 @@ impl<I: ConnId> QuicP2p<I> {
/// # Example
///
/// ```
/// use qp2p::{QuicP2p, Config, Error, ConnId};
/// use std::net::{IpAddr, Ipv4Addr, SocketAddr};
/// use qp2p::{QuicP2p, Config, ConnId};
/// use std::{error::Error, net::{IpAddr, Ipv4Addr, SocketAddr}};
///
/// # #[derive(Default, Ord, PartialEq, PartialOrd, Eq, Clone, Copy)]
/// # struct XId(pub [u8; 32]);
/// #
/// # impl ConnId for XId {
/// # fn generate(_socket_addr: &SocketAddr) -> Result<Self, Box<dyn std::error::Error>> {
/// # fn generate(_socket_addr: &SocketAddr) -> Result<Self, Box<dyn Error>> {
/// # Ok(XId(rand::random()))
/// # }
/// # }
///
/// #[tokio::main]
/// async fn main() -> Result<(), Error> {
/// async fn main() -> Result<(), Box<dyn Error>> {
/// let local_addr = (IpAddr::V4(Ipv4Addr::LOCALHOST), 3000).into();
/// let quic_p2p = QuicP2p::<XId>::with_config(Config::default())?;
/// let (mut endpoint, _, _, _) = quic_p2p.new_endpoint(local_addr).await?;
Expand Down Expand Up @@ -122,20 +122,20 @@ impl<I: ConnId> QuicP2p<I> {
/// # Example
///
/// ```
/// use qp2p::{QuicP2p, Config, Error, ConnId};
/// use std::net::{IpAddr, Ipv4Addr, SocketAddr};
/// use qp2p::{QuicP2p, Config, ConnId};
/// use std::{error::Error, net::{IpAddr, Ipv4Addr, SocketAddr}};
///
/// # #[derive(Default, Ord, PartialEq, PartialOrd, Eq, Clone, Copy)]
/// # struct XId(pub [u8; 32]);
/// #
/// # impl ConnId for XId {
/// # fn generate(_socket_addr: &SocketAddr) -> Result<Self, Box<dyn std::error::Error>> {
/// # fn generate(_socket_addr: &SocketAddr) -> Result<Self, Box<dyn Error>> {
/// # Ok(XId(rand::random()))
/// # }
/// # }
///
/// #[tokio::main]
/// async fn main() -> Result<(), Error> {
/// async fn main() -> Result<(), Box<dyn Error>> {
/// let local_addr = (IpAddr::V4(Ipv4Addr::LOCALHOST), 0).into();
/// let quic_p2p = QuicP2p::<XId>::with_config(Config::default())?;
/// let (endpoint, incoming_connections, incoming_messages, disconnections) = quic_p2p.new_endpoint(local_addr).await?;
Expand Down
51 changes: 46 additions & 5 deletions src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@

//! Configuration for `Endpoint`s.
use crate::error::{Error, Result};
use serde::{Deserialize, Serialize};
use std::{net::IpAddr, sync::Arc, time::Duration};
use structopt::StructOpt;
Expand All @@ -31,6 +30,46 @@ pub const DEFAULT_MIN_RETRY_DURATION: Duration = Duration::from_secs(30);

const MAIDSAFE_DOMAIN: &str = "maidsafe.net";

// Convenience alias – not for export.
type Result<T, E = ConfigError> = std::result::Result<T, E>;

/// Configuration errors.
#[derive(Debug, thiserror::Error)]
pub enum ConfigError {
/// An error occurred when generating the TLS certificate.
#[error("An error occurred when generating the TLS certificate")]
CertificateGeneration(#[from] CertificateGenerationError),
}

impl From<rcgen::RcgenError> for ConfigError {
fn from(error: rcgen::RcgenError) -> Self {
Self::CertificateGeneration(CertificateGenerationError(error.into()))
}
}

impl From<quinn::ParseError> for ConfigError {
fn from(error: quinn::ParseError) -> Self {
Self::CertificateGeneration(CertificateGenerationError(error.into()))
}
}

impl From<rustls::TLSError> for ConfigError {
fn from(error: rustls::TLSError) -> Self {
Self::CertificateGeneration(CertificateGenerationError(error.into()))
}
}

/// An error that occured when generating the TLS certificate.
#[derive(Debug, thiserror::Error)]
#[error(transparent)]
pub struct CertificateGenerationError(
// Though there are multiple different errors that could occur by the code, since we are
// generating a certificate, they should only really occur due to buggy implementations. As
// such, we don't attempt to expose more detail than 'something went wrong', which will
// hopefully be enough for someone to file a bug report...
Box<dyn std::error::Error + Send + Sync>,
);

/// QuicP2p configurations
#[derive(Clone, Debug, Default, Serialize, Deserialize, Eq, PartialEq, StructOpt)]
pub struct Config {
Expand Down Expand Up @@ -177,11 +216,13 @@ impl InternalConfig {

fn generate_cert() -> Result<(quinn::Certificate, quinn::PrivateKey)> {
let cert = rcgen::generate_simple_self_signed(vec![MAIDSAFE_DOMAIN.to_string()])?;

let cert_der = cert.serialize_der()?;
let key_der = cert.serialize_private_key_der();

Ok((
quinn::Certificate::from_der(&cert.serialize_der()?)
.map_err(|_| Error::CertificateParse)?,
quinn::PrivateKey::from_der(&cert.serialize_private_key_der())
.map_err(|_| Error::CertificatePkParse)?,
quinn::Certificate::from_der(&cert_der)?,
quinn::PrivateKey::from_der(&key_der)?,
))
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/connections.rs
Original file line number Diff line number Diff line change
Expand Up @@ -434,7 +434,7 @@ mod tests {
use anyhow::anyhow;

#[tokio::test(flavor = "multi_thread")]
async fn echo_service() -> Result<(), Error> {
async fn echo_service() -> Result<(), anyhow::Error> {
let qp2p = QuicP2p::<[u8; 32]>::with_config(Config::default())?;

// Create Endpoint
Expand Down
13 changes: 0 additions & 13 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,12 +47,6 @@ pub enum Error {
/// Failed to set/get priority of stream.
#[error("Unknown stream, cannot set/get priority.")]
UnknownStream,
/// Certificate for secure communication couldn't be parsed.
#[error("Cannot parse certificate ")]
CertificateParse,
/// The certificate's private key for secure communication couldn't be parsed.
#[error("Cannot parse certificate's private key")]
CertificatePkParse,
/// The contacts list was found empty when attempting
/// to contact peers for the echo service.
#[error("No peers found in the contacts list to send the echo request to")]
Expand All @@ -64,9 +58,6 @@ pub enum Error {
/// Failure occurred when sending an echo request.
#[error("{0}")]
EchoServiceFailure(String),
/// TLS error
#[error("TLS Error ")]
Tls(#[from] rustls::TLSError),
/// Serialisation error, which can happen on different type of data.
#[error("Serialisation error")]
Serialisation(#[from] bincode::Error),
Expand Down Expand Up @@ -97,10 +88,6 @@ pub enum Error {
/// IGD is not supported on IPv6
#[error("IGD is not supported on IPv6")]
IgdNotSupported,
/// An error was encountered when trying to either generate
/// or serialise a self-signed certificate.
#[error("Self-signed certificate generation error: {0}")]
CertificateGen(#[from] rcgen::RcgenError),
/// Response message received contains an empty payload.
#[error("Empty response message received from peer")]
EmptyResponse,
Expand Down
2 changes: 1 addition & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ mod utils;
mod wire_msg;

pub use api::QuicP2p;
pub use config::Config;
pub use config::{Config, ConfigError};
pub use connection_pool::ConnId;
pub use connections::{DisconnectionEvents, RecvStream, SendStream};
pub use endpoint::{Endpoint, IncomingConnections, IncomingMessages};
Expand Down

0 comments on commit e837aca

Please sign in to comment.