Skip to content

Commit

Permalink
feat: add MagicEndpoint to iroh-net
Browse files Browse the repository at this point in the history
  • Loading branch information
Frando committed Jul 3, 2023
1 parent 3dca612 commit 4597cb3
Show file tree
Hide file tree
Showing 18 changed files with 916 additions and 364 deletions.
12 changes: 6 additions & 6 deletions iroh-bytes/src/get.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,12 +69,12 @@ pub async fn run_ticket(
keylog: bool,
derp_map: Option<DerpMap>,
) -> Result<get_response_machine::AtInitial> {
let connection = iroh_net::client::dial_peer(
ticket.addrs(),
let connection = iroh_net::MagicEndpoint::dial_peer(
ticket.peer(),
&crate::P2P_ALPN,
keylog,
ticket.addrs(),
derp_map,
keylog,
)
.await?;

Expand Down Expand Up @@ -624,12 +624,12 @@ pub async fn run(
request: AnyGetRequest,
opts: Options,
) -> anyhow::Result<get_response_machine::AtInitial> {
let connection = iroh_net::client::dial_peer(
&opts.addrs,
let connection = iroh_net::MagicEndpoint::dial_peer(
opts.peer_id,
&crate::P2P_ALPN,
opts.keylog,
&opts.addrs,
opts.derp_map,
opts.keylog,
)
.await?;
Ok(run_connection(connection, request))
Expand Down
1 change: 1 addition & 0 deletions iroh-net/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ rtnetlink = "0.12.0"
wmi = "0.13"

[dev-dependencies]
clap = { version = "4", features = ["derive"] }
tokio = { version = "1", features = ["io-util", "sync", "rt", "net", "fs", "macros", "time", "test-util"] }
tracing-subscriber = { version = "0.3", features = ["env-filter"] }

Expand Down
137 changes: 137 additions & 0 deletions iroh-net/examples/magic.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
use std::net::SocketAddr;

use clap::Parser;
use ed25519_dalek::SigningKey as SecretKey;
use iroh_net::{
defaults::default_derp_map,
hp::derp::{DerpMap, UseIpv4, UseIpv6},
magic_endpoint::accept_conn,
tls::{Keypair, PeerId},
MagicEndpoint,
};
use tracing::{debug, info};
use url::Url;

const EXAMPLE_ALPN: &[u8] = b"n0/iroh/examples/magic/0";

#[derive(Debug, Parser)]
struct Cli {
#[clap(short, long)]
secret: Option<String>,
#[clap(short, long, default_value = "n0/iroh/examples/magic/0")]
alpn: String,
#[clap(short, long, default_value = "0")]
bind_port: u16,
#[clap(short, long)]
derp_url: Option<Url>,
#[clap(subcommand)]
command: Command,
}

#[derive(Debug, Parser)]
enum Command {
Listen,
Connect {
peer_id: String,
addrs: Option<Vec<SocketAddr>>,
},
}

#[tokio::main]
async fn main() -> anyhow::Result<()> {
tracing_subscriber::fmt::init();
let args = Cli::parse();
let keypair = match args.secret {
None => {
let keypair = Keypair::generate();
println!("our secret key: {}", fmt_secret(&keypair));
keypair
}
Some(key) => parse_secret(&key)?,
};

let derp_map = match args.derp_url {
None => default_derp_map(),
Some(url) => {
// TODO: This should be done by the DERP client.
let derp_port = match url.port() {
Some(port) => port,
None => match url.scheme() {
"http" => 80,
"https" => 443,
_ => anyhow::bail!(
"Invalid scheme in DERP URL, only http: and https: schemes are supported."
),
},
};
DerpMap::default_from_node(url, 3478, derp_port, UseIpv4::None, UseIpv6::None)
}
};

let endpoint = MagicEndpoint::builder()
.keypair(keypair)
.alpns(vec![args.alpn.to_string().into_bytes()])
.derp_map(Some(derp_map))
.bind(args.bind_port)
.await?;

let me = endpoint.peer_id();
let local_addr = endpoint.local_addr()?;
println!("magic socket listening on {local_addr:?}");
println!("our peer id: {me}");

match args.command {
Command::Listen => {
while let Some(conn) = endpoint.accept().await {
let (peer_id, alpn, conn) = accept_conn(conn).await?;
info!(
"new connection from {peer_id} with ALPN {alpn} (coming from {})",
conn.remote_address()
);
tokio::spawn(async move {
let (mut send, mut recv) = conn.accept_bi().await?;
debug!("accepted bi stream, waiting for data...");
let message = recv.read_to_end(1000).await?;
let message = String::from_utf8(message)?;
println!("received: {message}");

let message = format!("hi! you connected to {me}. bye bye");
send.write_all(message.as_bytes()).await?;
send.finish().await?;

Ok::<_, anyhow::Error>(())
});
}
}
Command::Connect { peer_id, addrs } => {
let peer_id: PeerId = peer_id.parse()?;
let addrs = addrs.unwrap_or_default();
let conn = endpoint.connect(peer_id, EXAMPLE_ALPN, &addrs).await?;
info!("connected");

let (mut send, mut recv) = conn.open_bi().await?;

let message = format!("hello here's {me}");
send.write_all(message.as_bytes()).await?;
send.finish().await?;
let message = recv.read_to_end(100).await?;
let message = String::from_utf8(message)?;
println!("received: {message}");
}
}
Ok(())
}

fn fmt_secret(keypair: &Keypair) -> String {
let mut text = data_encoding::BASE32_NOPAD.encode(&keypair.secret().to_bytes());
text.make_ascii_lowercase();
text
}
fn parse_secret(secret: &str) -> anyhow::Result<Keypair> {
let bytes: [u8; 32] = data_encoding::BASE32_NOPAD
.decode(secret.to_ascii_uppercase().as_bytes())?
.try_into()
.map_err(|_| anyhow::anyhow!("Invalid secret"))?;
let key = SecretKey::from_bytes(&bytes);
Ok(key.into())
}
145 changes: 0 additions & 145 deletions iroh-net/src/client.rs

This file was deleted.

30 changes: 30 additions & 0 deletions iroh-net/src/defaults.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
use std::collections::HashMap;

use crate::hp::derp::{DerpMap, DerpNode, DerpRegion, UseIpv4, UseIpv6};

pub fn default_derp_map() -> DerpMap {
DerpMap {
regions: HashMap::from_iter([(1, default_derp_region())].into_iter()),
}
}

pub fn default_derp_region() -> DerpRegion {
// The default derper run by number0.
let default_n0_derp = DerpNode {
name: "default-1".into(),
region_id: 1,
host_name: "https://derp.iroh.network".parse().unwrap(),
stun_only: false,
stun_port: 3478,
ipv4: UseIpv4::Some([35, 175, 99, 113].into()),
ipv6: UseIpv6::None,
derp_port: 443,
stun_test_ip: None,
};
DerpRegion {
region_id: 1,
nodes: vec![default_n0_derp],
avoid: false,
region_code: "default-1".into(),
}
}
2 changes: 1 addition & 1 deletion iroh-net/src/hp/cfg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ pub struct PingResult {
/// A node or peer in the iroh network.
///
/// Nodes are primarily identified by their [`Node::key`].
#[derive(Debug, PartialEq)]
#[derive(Clone, Debug, PartialEq)]
pub struct Node {
/// The public key or PeerID, the primary identifier of this node.
pub key: key::node::PublicKey,
Expand Down
2 changes: 1 addition & 1 deletion iroh-net/src/hp/hostinfo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ const RUST_VERSION: &str = env!("RUSTC_VERSION");
const GIT_COMMIT: &str = env!("GIT_COMMIT");

/// Contains a summary of the host we are running on.
#[derive(Debug, PartialEq)]
#[derive(Clone, Debug, PartialEq)]
pub struct Hostinfo {
/// Version of this code.
pub version: String,
Expand Down
5 changes: 4 additions & 1 deletion iroh-net/src/hp/magicsock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ mod rebinding_conn;
mod timer;
mod udp_actor;

pub use self::conn::{Conn, Options};
pub use self::conn::{Callbacks, Conn, Options};
pub use self::endpoint::EndpointInfo;
pub use self::timer::Timer;

#[cfg(test)]
pub(crate) use conn::tests as conn_tests;
Loading

0 comments on commit 4597cb3

Please sign in to comment.