Skip to content

Commit

Permalink
feat: direct connection callback
Browse files Browse the repository at this point in the history
first attempt for some kind of callback API for when a direct connection is established between an endpoint and a peer
  • Loading branch information
ramfox committed Apr 9, 2024
1 parent eb1417f commit a206749
Show file tree
Hide file tree
Showing 3 changed files with 79 additions and 2 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ required-features = ["headers"] # Do not build unless generating headers.
[dependencies]
anyhow = "1.0.79"
bytes = "1.5.0"
iroh-net = "0.13"
iroh-net = { git = "https://github.com/n0-computer/iroh.git", branch = "ramfox/alert-first-holepunch" }
once_cell = "1.19.0"
quinn = "0.10.2"
safer-ffi = { version = "0.1.5" }
Expand Down
19 changes: 19 additions & 0 deletions irohnet.h
Original file line number Diff line number Diff line change
Expand Up @@ -484,6 +484,25 @@ magic_endpoint_connect (
MagicEndpoint_t *
magic_endpoint_default (void);

/** \brief
* Run a callback once you have a direct connection to a peer
*
* Does not block, the provided callback will be called when we have a direct
* connection to the peer associated with the `node_id`, or the timeout has occurred.
*
* To wait indefinitely, provide -1 for the timeout parameter.
*
* `ctx` is passed along to the callback, to allow passing context, it must be thread safe as the callback is
* called from another thread.
*/
void
magic_endpoint_direct_conn_cb (
MagicEndpoint_t * ep,
void const * ctx,
PublicKey_t const * node_id,
ssize_t timeout,
void (*cb)(void const *, MagicEndpointResult_t));

/** \brief
* Frees the magic endpoint.
*/
Expand Down
60 changes: 59 additions & 1 deletion src/magic_endpoint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use tokio::sync::RwLock;
use tracing::{debug, warn};

use crate::addr::NodeAddr;
use crate::key::{secret_key_generate, SecretKey};
use crate::key::{secret_key_generate, PublicKey, SecretKey};
use crate::stream::{RecvStream, SendStream};
use crate::util::TOKIO_EXECUTOR;

Expand Down Expand Up @@ -596,6 +596,64 @@ pub fn magic_endpoint_accept_any_cb(
});
}

/// Run a callback once you have a direct connection to a peer
///
/// Does not block, the provided callback will be called when we have a direct
/// connection to the peer associated with the `node_id`, or the timeout has occurred.
///
/// To wait indefinitely, provide -1 for the timeout parameter.
///
/// `ctx` is passed along to the callback, to allow passing context, it must be thread safe as the callback is
/// called from another thread.
#[ffi_export]
pub fn magic_endpoint_direct_conn_cb(
ep: repr_c::Box<MagicEndpoint>,
ctx: *const c_void,
node_id: &PublicKey,
timeout: isize,
cb: unsafe extern "C" fn(ctx: *const c_void, err: MagicEndpointResult),
) {
// hack around the fact that `*const c_void` is not Send
struct CtxPtr(*const c_void);
unsafe impl Send for CtxPtr {}
let ctx_ptr = CtxPtr(ctx);

let node_id: iroh_net::key::PublicKey = node_id.into();

TOKIO_EXECUTOR.spawn(async move {
// make the compiler happy
let _ = &ctx_ptr;
let timeout = if timeout == -1 {
None
} else {
Some(Duration::from_millis(timeout as u64))
};
async fn connect(
ep: repr_c::Box<MagicEndpoint>,
node_id: iroh_net::key::PublicKey,
timeout: Option<Duration>,
) -> anyhow::Result<()> {
ep.ep
.read()
.await
.as_ref()
.expect("endpoint not initalized")
.wait_for_direct_connection(&node_id, timeout)
.await
}

match connect(ep, node_id, timeout).await {
Ok(()) => unsafe {
cb(ctx_ptr.0, MagicEndpointResult::Ok);
},
Err(err) => unsafe {
warn!("accept failed: {:?}", err);
cb(ctx_ptr.0, MagicEndpointResult::AcceptFailed);
},
}
});
}

/// Establish a uni directional connection.
///
/// Blocks the current thread until the connection is established.
Expand Down

0 comments on commit a206749

Please sign in to comment.