logging refactor
This commit is contained in:
282
veilid-core/src/rpc_processor/debug.rs
Normal file
282
veilid-core/src/rpc_processor/debug.rs
Normal file
@@ -0,0 +1,282 @@
|
||||
use super::*;
|
||||
|
||||
#[derive(Debug, Clone, PartialOrd, PartialEq, Eq, Ord)]
|
||||
pub enum RPCError {
|
||||
Timeout,
|
||||
InvalidFormat,
|
||||
Unimplemented(String),
|
||||
Protocol(String),
|
||||
Internal(String),
|
||||
}
|
||||
pub fn rpc_error_internal<T: AsRef<str>>(x: T) -> RPCError {
|
||||
error!("RPCError Internal: {}", x.as_ref());
|
||||
RPCError::Internal(x.as_ref().to_owned())
|
||||
}
|
||||
pub fn rpc_error_capnp_error(e: capnp::Error) -> RPCError {
|
||||
error!("RPCError Protocol: {}", &e.description);
|
||||
RPCError::Protocol(e.description)
|
||||
}
|
||||
pub fn rpc_error_capnp_notinschema(e: capnp::NotInSchema) -> RPCError {
|
||||
error!("RPCError Protocol: not in schema: {}", &e.0);
|
||||
RPCError::Protocol(format!("not in schema: {}", &e.0))
|
||||
}
|
||||
pub fn rpc_error_unimplemented<T: AsRef<str>>(x: T) -> RPCError {
|
||||
error!("RPCError Unimplemented: {}", x.as_ref());
|
||||
RPCError::Unimplemented(x.as_ref().to_owned())
|
||||
}
|
||||
|
||||
impl fmt::Display for RPCError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
RPCError::Timeout => write!(f, "[RPCError: Timeout]"),
|
||||
RPCError::InvalidFormat => write!(f, "[RPCError: InvalidFormat]"),
|
||||
RPCError::Unimplemented(s) => write!(f, "[RPCError: Unimplemented({})]", s),
|
||||
RPCError::Protocol(s) => write!(f, "[RPCError: Protocol({})]", s),
|
||||
RPCError::Internal(s) => write!(f, "[RPCError: Internal({})]", s),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! map_error_internal {
|
||||
($x:expr) => {
|
||||
|_| rpc_error_internal($x)
|
||||
};
|
||||
}
|
||||
#[macro_export]
|
||||
macro_rules! map_error_string {
|
||||
() => {
|
||||
|s| rpc_error_internal(&s)
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! map_error_capnp_error {
|
||||
() => {
|
||||
|e| rpc_error_capnp_error(e)
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! map_error_capnp_notinschema {
|
||||
() => {
|
||||
|e| rpc_error_capnp_notinschema(e)
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! map_error_panic {
|
||||
() => {
|
||||
|_| panic!("oops")
|
||||
};
|
||||
}
|
||||
|
||||
impl RPCProcessor {
|
||||
pub(super) fn get_rpc_request_debug_info<T: capnp::message::ReaderSegments>(
|
||||
&self,
|
||||
dest: &Destination,
|
||||
message: &capnp::message::Reader<T>,
|
||||
safety_route_spec: &Option<&SafetyRouteSpec>,
|
||||
) -> String {
|
||||
format!(
|
||||
"REQ->{:?}{} {}",
|
||||
dest,
|
||||
match safety_route_spec {
|
||||
None => "".to_owned(),
|
||||
Some(srs) => format!("[{:?}]", srs),
|
||||
},
|
||||
self.get_rpc_message_debug_info(message)
|
||||
)
|
||||
}
|
||||
pub(super) fn get_rpc_reply_debug_info<T: capnp::message::ReaderSegments>(
|
||||
&self,
|
||||
request_rpcreader: &RPCMessageReader,
|
||||
reply_msg: &capnp::message::Reader<T>,
|
||||
safety_route_spec: &Option<&SafetyRouteSpec>,
|
||||
) -> String {
|
||||
let request_operation = match request_rpcreader
|
||||
.reader
|
||||
.get_root::<veilid_capnp::operation::Reader>()
|
||||
{
|
||||
Ok(v) => v,
|
||||
Err(e) => {
|
||||
return format!("invalid operation: {}", e);
|
||||
}
|
||||
};
|
||||
|
||||
let respond_to = match request_operation.get_respond_to().which() {
|
||||
Ok(v) => v,
|
||||
Err(e) => {
|
||||
return format!("(respond_to not in schema: {:?})", e);
|
||||
}
|
||||
};
|
||||
let respond_to_str = match respond_to {
|
||||
veilid_capnp::operation::respond_to::None(_) => "(None)".to_owned(),
|
||||
veilid_capnp::operation::respond_to::Sender(_) => "Sender".to_owned(),
|
||||
veilid_capnp::operation::respond_to::PrivateRoute(pr) => {
|
||||
let pr_reader = match pr {
|
||||
Ok(prr) => prr,
|
||||
Err(e) => {
|
||||
return e.to_string();
|
||||
}
|
||||
};
|
||||
let private_route = match decode_private_route(&pr_reader) {
|
||||
Ok(pr) => pr,
|
||||
Err(e) => {
|
||||
return e.to_string();
|
||||
}
|
||||
};
|
||||
format!("[PR:{:?}]", private_route)
|
||||
}
|
||||
};
|
||||
format!(
|
||||
"REPLY->{:?}{} {}",
|
||||
respond_to_str,
|
||||
match safety_route_spec {
|
||||
None => "".to_owned(),
|
||||
Some(srs) => format!("[SR:{:?}]", srs),
|
||||
},
|
||||
self.get_rpc_message_debug_info(reply_msg)
|
||||
)
|
||||
}
|
||||
|
||||
pub(super) fn get_rpc_message_debug_info<T: capnp::message::ReaderSegments>(
|
||||
&self,
|
||||
message: &capnp::message::Reader<T>,
|
||||
) -> String {
|
||||
let operation = match message.get_root::<veilid_capnp::operation::Reader>() {
|
||||
Ok(v) => v,
|
||||
Err(e) => {
|
||||
return format!("invalid operation: {}", e);
|
||||
}
|
||||
};
|
||||
let op_id = operation.get_op_id();
|
||||
let detail = match operation.get_detail().which() {
|
||||
Ok(v) => v,
|
||||
Err(e) => {
|
||||
return format!("(operation detail not in schema: {})", e);
|
||||
}
|
||||
};
|
||||
format!(
|
||||
"#{} {}",
|
||||
op_id,
|
||||
self.get_rpc_operation_detail_debug_info(&detail)
|
||||
)
|
||||
}
|
||||
|
||||
#[allow(clippy::useless_format)]
|
||||
pub(super) fn get_rpc_operation_detail_debug_info(
|
||||
&self,
|
||||
detail: &veilid_capnp::operation::detail::WhichReader,
|
||||
) -> String {
|
||||
match detail {
|
||||
veilid_capnp::operation::detail::InfoQ(_) => {
|
||||
format!("InfoQ")
|
||||
}
|
||||
veilid_capnp::operation::detail::InfoA(_) => {
|
||||
format!("InfoA")
|
||||
}
|
||||
veilid_capnp::operation::detail::ValidateDialInfo(_) => {
|
||||
format!("ValidateDialInfo")
|
||||
}
|
||||
veilid_capnp::operation::detail::FindNodeQ(d) => {
|
||||
let fnqr = match d {
|
||||
Ok(fnqr) => fnqr,
|
||||
Err(e) => {
|
||||
return format!("(invalid detail: {})", e);
|
||||
}
|
||||
};
|
||||
let nidr = match fnqr.get_node_id() {
|
||||
Ok(nidr) => nidr,
|
||||
Err(e) => {
|
||||
return format!("(invalid node id: {})", e);
|
||||
}
|
||||
};
|
||||
let pir = match fnqr.get_peer_info() {
|
||||
Ok(pir) => pir,
|
||||
Err(e) => {
|
||||
return format!("(invalid peer_info: {})", e);
|
||||
}
|
||||
};
|
||||
let node_id = decode_public_key(&nidr);
|
||||
let peer_info = match decode_peer_info(&pir) {
|
||||
Ok(pi) => pi,
|
||||
Err(e) => {
|
||||
return e.to_string();
|
||||
}
|
||||
};
|
||||
format!(
|
||||
"FindNodeQ: node_id={} peer_info={:?}",
|
||||
node_id.encode(),
|
||||
peer_info
|
||||
)
|
||||
}
|
||||
veilid_capnp::operation::detail::FindNodeA(_) => {
|
||||
format!("FindNodeA")
|
||||
}
|
||||
veilid_capnp::operation::detail::Route(_) => {
|
||||
format!("Route")
|
||||
}
|
||||
veilid_capnp::operation::detail::GetValueQ(_) => {
|
||||
format!("GetValueQ")
|
||||
}
|
||||
veilid_capnp::operation::detail::GetValueA(_) => {
|
||||
format!("GetValueA")
|
||||
}
|
||||
veilid_capnp::operation::detail::SetValueQ(_) => {
|
||||
format!("SetValueQ")
|
||||
}
|
||||
veilid_capnp::operation::detail::SetValueA(_) => {
|
||||
format!("SetValueA")
|
||||
}
|
||||
veilid_capnp::operation::detail::WatchValueQ(_) => {
|
||||
format!("WatchValueQ")
|
||||
}
|
||||
veilid_capnp::operation::detail::WatchValueA(_) => {
|
||||
format!("WatchValueA")
|
||||
}
|
||||
veilid_capnp::operation::detail::ValueChanged(_) => {
|
||||
format!("ValueChanged")
|
||||
}
|
||||
veilid_capnp::operation::detail::SupplyBlockQ(_) => {
|
||||
format!("SupplyBlockQ")
|
||||
}
|
||||
veilid_capnp::operation::detail::SupplyBlockA(_) => {
|
||||
format!("SupplyBlockA")
|
||||
}
|
||||
veilid_capnp::operation::detail::FindBlockQ(_) => {
|
||||
format!("FindBlockQ")
|
||||
}
|
||||
veilid_capnp::operation::detail::FindBlockA(_) => {
|
||||
format!("FindBlockA")
|
||||
}
|
||||
veilid_capnp::operation::detail::SignalQ(_) => {
|
||||
format!("SignalQ")
|
||||
}
|
||||
veilid_capnp::operation::detail::SignalA(_) => {
|
||||
format!("SignalA")
|
||||
}
|
||||
veilid_capnp::operation::detail::ReturnReceipt(_) => {
|
||||
format!("ReturnReceipt")
|
||||
}
|
||||
veilid_capnp::operation::detail::StartTunnelQ(_) => {
|
||||
format!("StartTunnelQ")
|
||||
}
|
||||
veilid_capnp::operation::detail::StartTunnelA(_) => {
|
||||
format!("StartTunnelA")
|
||||
}
|
||||
veilid_capnp::operation::detail::CompleteTunnelQ(_) => {
|
||||
format!("CompleteTunnelQ")
|
||||
}
|
||||
veilid_capnp::operation::detail::CompleteTunnelA(_) => {
|
||||
format!("CompleteTunnelA")
|
||||
}
|
||||
veilid_capnp::operation::detail::CancelTunnelQ(_) => {
|
||||
format!("CancelTunnelQ")
|
||||
}
|
||||
veilid_capnp::operation::detail::CancelTunnelA(_) => {
|
||||
format!("CancelTunnelA")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,4 +1,9 @@
|
||||
mod coders;
|
||||
mod debug;
|
||||
mod private_route;
|
||||
|
||||
pub use debug::*;
|
||||
pub use private_route::*;
|
||||
|
||||
use crate::dht::*;
|
||||
use crate::intf::utils::channel::*;
|
||||
@@ -18,77 +23,6 @@ use routing_table::*;
|
||||
|
||||
type OperationId = u64;
|
||||
|
||||
#[derive(Debug, Clone, PartialOrd, PartialEq, Eq, Ord)]
|
||||
pub enum RPCError {
|
||||
Timeout,
|
||||
InvalidFormat,
|
||||
Unimplemented(String),
|
||||
Protocol(String),
|
||||
Internal(String),
|
||||
}
|
||||
pub fn rpc_error_internal<T: AsRef<str>>(x: T) -> RPCError {
|
||||
error!("RPCError Internal: {}", x.as_ref());
|
||||
RPCError::Internal(x.as_ref().to_owned())
|
||||
}
|
||||
pub fn rpc_error_capnp_error(e: capnp::Error) -> RPCError {
|
||||
error!("RPCError Protocol: {}", &e.description);
|
||||
RPCError::Protocol(e.description)
|
||||
}
|
||||
pub fn rpc_error_capnp_notinschema(e: capnp::NotInSchema) -> RPCError {
|
||||
error!("RPCError Protocol: not in schema: {}", &e.0);
|
||||
RPCError::Protocol(format!("not in schema: {}", &e.0))
|
||||
}
|
||||
pub fn rpc_error_unimplemented<T: AsRef<str>>(x: T) -> RPCError {
|
||||
error!("RPCError Unimplemented: {}", x.as_ref());
|
||||
RPCError::Unimplemented(x.as_ref().to_owned())
|
||||
}
|
||||
|
||||
impl fmt::Display for RPCError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
RPCError::Timeout => write!(f, "[RPCError: Timeout]"),
|
||||
RPCError::InvalidFormat => write!(f, "[RPCError: InvalidFormat]"),
|
||||
RPCError::Unimplemented(s) => write!(f, "[RPCError: Unimplemented({})]", s),
|
||||
RPCError::Protocol(s) => write!(f, "[RPCError: Protocol({})]", s),
|
||||
RPCError::Internal(s) => write!(f, "[RPCError: Internal({})]", s),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! map_error_internal {
|
||||
($x:expr) => {
|
||||
|_| rpc_error_internal($x)
|
||||
};
|
||||
}
|
||||
#[macro_export]
|
||||
macro_rules! map_error_string {
|
||||
() => {
|
||||
|s| rpc_error_internal(&s)
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! map_error_capnp_error {
|
||||
() => {
|
||||
|e| rpc_error_capnp_error(e)
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! map_error_capnp_notinschema {
|
||||
() => {
|
||||
|e| rpc_error_capnp_notinschema(e)
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! map_error_panic {
|
||||
() => {
|
||||
|_| panic!("oops")
|
||||
};
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum Destination {
|
||||
Direct(NodeRef),
|
||||
@@ -207,7 +141,7 @@ pub struct RPCProcessorInner {
|
||||
routing_table: RoutingTable,
|
||||
node_id: key::DHTKey,
|
||||
node_id_secret: key::DHTKeySecret,
|
||||
channel: Option<(Sender<RPCMessage>, Receiver<RPCMessage>)>,
|
||||
send_channel: Option<Sender<RPCMessage>>,
|
||||
timeout: u64,
|
||||
max_route_hop_count: usize,
|
||||
waiting_rpc_table: BTreeMap<OperationId, EventualValue<RPCMessageReader>>,
|
||||
@@ -228,7 +162,7 @@ impl RPCProcessor {
|
||||
routing_table: network_manager.routing_table(),
|
||||
node_id: key::DHTKey::default(),
|
||||
node_id_secret: key::DHTKeySecret::default(),
|
||||
channel: None,
|
||||
send_channel: None,
|
||||
timeout: 10000000,
|
||||
max_route_hop_count: 7,
|
||||
waiting_rpc_table: BTreeMap::new(),
|
||||
@@ -327,197 +261,6 @@ impl RPCProcessor {
|
||||
Ok(nr)
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
fn new_stub_private_route<'a, T>(
|
||||
&self,
|
||||
dest_node_id: key::DHTKey,
|
||||
builder: &'a mut ::capnp::message::Builder<T>,
|
||||
) -> Result<veilid_capnp::private_route::Reader<'a>, RPCError>
|
||||
where
|
||||
T: capnp::message::Allocator + 'a,
|
||||
{
|
||||
let mut pr = builder.init_root::<veilid_capnp::private_route::Builder>();
|
||||
|
||||
let mut pr_pk = pr.reborrow().init_public_key();
|
||||
encode_public_key(&dest_node_id, &mut pr_pk)?;
|
||||
pr.set_hop_count(0u8);
|
||||
// leave firstHop as null
|
||||
Ok(pr.into_reader())
|
||||
}
|
||||
|
||||
fn encode_safety_route<'a>(
|
||||
&self,
|
||||
safety_route: &SafetyRouteSpec,
|
||||
private_route: veilid_capnp::private_route::Reader<'a>,
|
||||
builder: &'a mut veilid_capnp::safety_route::Builder<'a>,
|
||||
) -> Result<(), RPCError> {
|
||||
// Ensure the total hop count isn't too long for our config
|
||||
let pr_hopcount = private_route.get_hop_count() as usize;
|
||||
let sr_hopcount = safety_route.hops.len();
|
||||
let hopcount = 1 + sr_hopcount + pr_hopcount;
|
||||
if hopcount > self.inner.lock().max_route_hop_count {
|
||||
return Err(rpc_error_internal("hop count too long for route"));
|
||||
}
|
||||
|
||||
// Build the safety route
|
||||
let mut sr_pk = builder.reborrow().init_public_key();
|
||||
encode_public_key(&safety_route.public_key, &mut sr_pk)?;
|
||||
|
||||
builder.set_hop_count(
|
||||
u8::try_from(sr_hopcount)
|
||||
.map_err(map_error_internal!("hop count too large for safety route"))?,
|
||||
);
|
||||
|
||||
// Build all the hops in the safety route
|
||||
let mut hops_builder = builder.reborrow().init_hops();
|
||||
if sr_hopcount == 0 {
|
||||
hops_builder
|
||||
.set_private(private_route)
|
||||
.map_err(map_error_internal!(
|
||||
"invalid private route while encoding safety route"
|
||||
))?;
|
||||
} else {
|
||||
// start last blob-to-encrypt data off as private route
|
||||
let mut blob_data = {
|
||||
let mut pr_message = ::capnp::message::Builder::new_default();
|
||||
pr_message
|
||||
.set_root_canonical(private_route)
|
||||
.map_err(map_error_internal!(
|
||||
"invalid private route while encoding safety route"
|
||||
))?;
|
||||
let mut blob_data = builder_to_vec(pr_message)?;
|
||||
// append the private route tag so we know how to decode it later
|
||||
blob_data.push(1u8);
|
||||
blob_data
|
||||
};
|
||||
|
||||
// Encode each hop from inside to outside
|
||||
// skips the outermost hop since that's entering the
|
||||
// safety route and does not include the dialInfo
|
||||
// (outer hop is a RouteHopData, not a RouteHop).
|
||||
// Each loop mutates 'nonce', and 'blob_data'
|
||||
let mut nonce = Crypto::get_random_nonce();
|
||||
for h in (1..sr_hopcount).rev() {
|
||||
// Get blob to encrypt for next hop
|
||||
blob_data = {
|
||||
// RouteHop
|
||||
let mut rh_message = ::capnp::message::Builder::new_default();
|
||||
let mut rh_builder = rh_message.init_root::<veilid_capnp::route_hop::Builder>();
|
||||
let mut di_builder = rh_builder.reborrow().init_dial_info();
|
||||
encode_node_dial_info_single(&safety_route.hops[h].dial_info, &mut di_builder)?;
|
||||
// RouteHopData
|
||||
let mut rhd_builder = rh_builder.init_next_hop();
|
||||
// Add the nonce
|
||||
let mut rhd_nonce = rhd_builder.reborrow().init_nonce();
|
||||
encode_nonce(&nonce, &mut rhd_nonce);
|
||||
// Encrypt the previous blob ENC(nonce, DH(PKhop,SKsr))
|
||||
let dh_secret = self
|
||||
.crypto
|
||||
.cached_dh(
|
||||
&safety_route.hops[h].dial_info.node_id.key,
|
||||
&safety_route.secret_key,
|
||||
)
|
||||
.map_err(map_error_internal!("dh failed"))?;
|
||||
let enc_msg_data =
|
||||
Crypto::encrypt(blob_data.as_slice(), &nonce, &dh_secret, None)
|
||||
.map_err(map_error_internal!("encryption failed"))?;
|
||||
|
||||
rhd_builder.set_blob(enc_msg_data.as_slice());
|
||||
let mut blob_data = builder_to_vec(rh_message)?;
|
||||
|
||||
// append the route hop tag so we know how to decode it later
|
||||
blob_data.push(0u8);
|
||||
blob_data
|
||||
};
|
||||
// Make another nonce for the next hop
|
||||
nonce = Crypto::get_random_nonce();
|
||||
}
|
||||
|
||||
// Encode first RouteHopData
|
||||
let mut first_rhd_builder = hops_builder.init_data();
|
||||
let mut first_rhd_nonce = first_rhd_builder.reborrow().init_nonce();
|
||||
encode_nonce(&nonce, &mut first_rhd_nonce);
|
||||
let dh_secret = self
|
||||
.crypto
|
||||
.cached_dh(
|
||||
&safety_route.hops[0].dial_info.node_id.key,
|
||||
&safety_route.secret_key,
|
||||
)
|
||||
.map_err(map_error_internal!("dh failed"))?;
|
||||
let enc_msg_data = Crypto::encrypt(blob_data.as_slice(), &nonce, &dh_secret, None)
|
||||
.map_err(map_error_internal!("encryption failed"))?;
|
||||
|
||||
first_rhd_builder.set_blob(enc_msg_data.as_slice());
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// Wrap an operation inside a route
|
||||
fn wrap_with_route<'a>(
|
||||
&self,
|
||||
safety_route: Option<&SafetyRouteSpec>,
|
||||
private_route: veilid_capnp::private_route::Reader<'a>,
|
||||
message_data: Vec<u8>,
|
||||
) -> Result<Vec<u8>, RPCError> {
|
||||
// Get stuff before we lock inner
|
||||
let op_id = self.get_next_op_id();
|
||||
// Encrypt routed operation
|
||||
let nonce = Crypto::get_random_nonce();
|
||||
let pr_pk_reader = private_route
|
||||
.get_public_key()
|
||||
.map_err(map_error_internal!("public key is invalid"))?;
|
||||
let pr_pk = decode_public_key(&pr_pk_reader);
|
||||
let stub_safety_route = SafetyRouteSpec::new();
|
||||
let sr = safety_route.unwrap_or(&stub_safety_route);
|
||||
let dh_secret = self
|
||||
.crypto
|
||||
.cached_dh(&pr_pk, &sr.secret_key)
|
||||
.map_err(map_error_internal!("dh failed"))?;
|
||||
let enc_msg_data = Crypto::encrypt(&message_data, &nonce, &dh_secret, None)
|
||||
.map_err(map_error_internal!("encryption failed"))?;
|
||||
|
||||
// Prepare route operation
|
||||
let route_msg = {
|
||||
let mut route_msg = ::capnp::message::Builder::new_default();
|
||||
let mut route_operation = route_msg.init_root::<veilid_capnp::operation::Builder>();
|
||||
|
||||
// Doesn't matter what this op id because there's no answer
|
||||
// but it shouldn't conflict with any other op id either
|
||||
route_operation.set_op_id(op_id);
|
||||
|
||||
// Answers don't get a 'respond'
|
||||
let mut respond_to = route_operation.reborrow().init_respond_to();
|
||||
respond_to.set_none(());
|
||||
|
||||
// Set up 'route' operation
|
||||
let mut route = route_operation.reborrow().init_detail().init_route();
|
||||
|
||||
// Set the safety route we've constructed
|
||||
let mut msg_sr = route.reborrow().init_safety_route();
|
||||
self.encode_safety_route(sr, private_route, &mut msg_sr)?;
|
||||
|
||||
// Put in the encrypted operation we're routing
|
||||
let mut msg_operation = route.init_operation();
|
||||
msg_operation.reborrow().init_signatures(0);
|
||||
let mut route_nonce = msg_operation.reborrow().init_nonce();
|
||||
encode_nonce(&nonce, &mut route_nonce);
|
||||
let data = msg_operation.reborrow().init_data(
|
||||
enc_msg_data
|
||||
.len()
|
||||
.try_into()
|
||||
.map_err(map_error_internal!("data too large"))?,
|
||||
);
|
||||
data.copy_from_slice(enc_msg_data.as_slice());
|
||||
|
||||
route_msg
|
||||
};
|
||||
|
||||
// Convert message to bytes and return it
|
||||
let out = builder_to_vec(route_msg)?;
|
||||
Ok(out)
|
||||
}
|
||||
|
||||
// set up wait for reply
|
||||
fn add_op_id_waiter(&self, op_id: OperationId) -> EventualValue<RPCMessageReader> {
|
||||
let mut inner = self.inner.lock();
|
||||
@@ -619,6 +362,8 @@ impl RPCProcessor {
|
||||
message: capnp::message::Reader<T>,
|
||||
safety_route_spec: Option<&SafetyRouteSpec>,
|
||||
) -> Result<Option<WaitableReply>, RPCError> {
|
||||
log_rpc!(self.get_rpc_request_debug_info(&dest, &message, &safety_route_spec));
|
||||
|
||||
let (op_id, wants_answer, is_ping) = {
|
||||
let operation = message
|
||||
.get_root::<veilid_capnp::operation::Reader>()
|
||||
@@ -626,6 +371,7 @@ impl RPCProcessor {
|
||||
let op_id = operation.get_op_id();
|
||||
let wants_answer = self.wants_answer(&operation)?;
|
||||
let is_ping = operation.get_detail().has_info_q();
|
||||
|
||||
(op_id, wants_answer, is_ping)
|
||||
};
|
||||
|
||||
@@ -727,7 +473,9 @@ impl RPCProcessor {
|
||||
let node_ref = match out_noderef {
|
||||
None => {
|
||||
// resolve node
|
||||
self.resolve_node(out_node_id).await?
|
||||
self.resolve_node(out_node_id)
|
||||
.await
|
||||
.map_err(logthru_rpc!(error))?
|
||||
}
|
||||
Some(nr) => {
|
||||
// got the node in the routing table already
|
||||
@@ -748,6 +496,7 @@ impl RPCProcessor {
|
||||
.network_manager()
|
||||
.send_envelope(node_ref.clone(), out)
|
||||
.await
|
||||
.map_err(logthru_rpc!(error))
|
||||
.map_err(RPCError::Internal)
|
||||
{
|
||||
// Make sure to clean up op id waiter in case of error
|
||||
@@ -792,6 +541,8 @@ impl RPCProcessor {
|
||||
reply_msg: capnp::message::Reader<T>,
|
||||
safety_route_spec: Option<&SafetyRouteSpec>,
|
||||
) -> Result<(), RPCError> {
|
||||
log_rpc!(self.get_rpc_reply_debug_info(&request_rpcreader, &reply_msg, &safety_route_spec));
|
||||
|
||||
//
|
||||
let out_node_id;
|
||||
let mut out_noderef: Option<NodeRef> = None;
|
||||
@@ -821,7 +572,7 @@ impl RPCProcessor {
|
||||
veilid_capnp::operation::respond_to::None(_) => {
|
||||
// Do not respond
|
||||
// --------------
|
||||
return Ok(());
|
||||
return Err(rpc_error_internal("no response requested"));
|
||||
}
|
||||
veilid_capnp::operation::respond_to::Sender(_) => {
|
||||
// Respond to envelope source node, possibly through a relay if the request arrived that way
|
||||
@@ -1329,7 +1080,6 @@ impl RPCProcessor {
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
async fn process_rpc_message_version_0(&self, msg: RPCMessage) -> Result<(), RPCError> {
|
||||
let reader = capnp::message::Reader::new(msg.data, Default::default());
|
||||
let rpcreader = RPCMessageReader {
|
||||
@@ -1442,9 +1192,10 @@ impl RPCProcessor {
|
||||
|
||||
async fn rpc_worker(self, receiver: Receiver<RPCMessage>) {
|
||||
while let Ok(msg) = receiver.recv().await {
|
||||
if let Err(e) = self.process_rpc_message(msg).await {
|
||||
error!("Couldn't process rpc message: {}", e);
|
||||
}
|
||||
let _ = self
|
||||
.process_rpc_message(msg)
|
||||
.await
|
||||
.map_err(logthru_rpc!("couldn't process rpc message"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1479,7 +1230,7 @@ impl RPCProcessor {
|
||||
inner.timeout = timeout;
|
||||
inner.max_route_hop_count = max_route_hop_count;
|
||||
let channel = channel(queue_size as usize);
|
||||
inner.channel = Some(channel.clone());
|
||||
inner.send_channel = Some(channel.0.clone());
|
||||
|
||||
// spin up N workers
|
||||
trace!("Spinning up {} RPC workers", concurrency);
|
||||
@@ -1502,8 +1253,7 @@ impl RPCProcessor {
|
||||
envelope: envelope::Envelope,
|
||||
body: Vec<u8>,
|
||||
peer_noderef: NodeRef,
|
||||
) -> Result<(), ()> {
|
||||
trace!("enqueue_message: body len = {}", body.len());
|
||||
) -> Result<(), String> {
|
||||
let msg = RPCMessage {
|
||||
header: RPCMessageHeader {
|
||||
timestamp: get_timestamp(),
|
||||
@@ -1515,9 +1265,12 @@ impl RPCProcessor {
|
||||
};
|
||||
let send_channel = {
|
||||
let inner = self.inner.lock();
|
||||
inner.channel.as_ref().unwrap().0.clone()
|
||||
inner.send_channel.as_ref().unwrap().clone()
|
||||
};
|
||||
send_channel.try_send(msg).await.map_err(drop)?;
|
||||
send_channel
|
||||
.try_send(msg)
|
||||
.await
|
||||
.map_err(|e| format!("failed to enqueue received RPC message: {:?}", e))?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
194
veilid-core/src/rpc_processor/private_route.rs
Normal file
194
veilid-core/src/rpc_processor/private_route.rs
Normal file
@@ -0,0 +1,194 @@
|
||||
use super::*;
|
||||
|
||||
impl RPCProcessor {
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
pub(super) fn new_stub_private_route<'a, T>(
|
||||
&self,
|
||||
dest_node_id: key::DHTKey,
|
||||
builder: &'a mut ::capnp::message::Builder<T>,
|
||||
) -> Result<veilid_capnp::private_route::Reader<'a>, RPCError>
|
||||
where
|
||||
T: capnp::message::Allocator + 'a,
|
||||
{
|
||||
let mut pr = builder.init_root::<veilid_capnp::private_route::Builder>();
|
||||
|
||||
let mut pr_pk = pr.reborrow().init_public_key();
|
||||
encode_public_key(&dest_node_id, &mut pr_pk)?;
|
||||
pr.set_hop_count(0u8);
|
||||
// leave firstHop as null
|
||||
Ok(pr.into_reader())
|
||||
}
|
||||
|
||||
fn encode_safety_route<'a>(
|
||||
&self,
|
||||
safety_route: &SafetyRouteSpec,
|
||||
private_route: veilid_capnp::private_route::Reader<'a>,
|
||||
builder: &'a mut veilid_capnp::safety_route::Builder<'a>,
|
||||
) -> Result<(), RPCError> {
|
||||
// Ensure the total hop count isn't too long for our config
|
||||
let pr_hopcount = private_route.get_hop_count() as usize;
|
||||
let sr_hopcount = safety_route.hops.len();
|
||||
let hopcount = 1 + sr_hopcount + pr_hopcount;
|
||||
if hopcount > self.inner.lock().max_route_hop_count {
|
||||
return Err(rpc_error_internal("hop count too long for route"));
|
||||
}
|
||||
|
||||
// Build the safety route
|
||||
let mut sr_pk = builder.reborrow().init_public_key();
|
||||
encode_public_key(&safety_route.public_key, &mut sr_pk)?;
|
||||
|
||||
builder.set_hop_count(
|
||||
u8::try_from(sr_hopcount)
|
||||
.map_err(map_error_internal!("hop count too large for safety route"))?,
|
||||
);
|
||||
|
||||
// Build all the hops in the safety route
|
||||
let mut hops_builder = builder.reborrow().init_hops();
|
||||
if sr_hopcount == 0 {
|
||||
hops_builder
|
||||
.set_private(private_route)
|
||||
.map_err(map_error_internal!(
|
||||
"invalid private route while encoding safety route"
|
||||
))?;
|
||||
} else {
|
||||
// start last blob-to-encrypt data off as private route
|
||||
let mut blob_data = {
|
||||
let mut pr_message = ::capnp::message::Builder::new_default();
|
||||
pr_message
|
||||
.set_root_canonical(private_route)
|
||||
.map_err(map_error_internal!(
|
||||
"invalid private route while encoding safety route"
|
||||
))?;
|
||||
let mut blob_data = builder_to_vec(pr_message)?;
|
||||
// append the private route tag so we know how to decode it later
|
||||
blob_data.push(1u8);
|
||||
blob_data
|
||||
};
|
||||
|
||||
// Encode each hop from inside to outside
|
||||
// skips the outermost hop since that's entering the
|
||||
// safety route and does not include the dialInfo
|
||||
// (outer hop is a RouteHopData, not a RouteHop).
|
||||
// Each loop mutates 'nonce', and 'blob_data'
|
||||
let mut nonce = Crypto::get_random_nonce();
|
||||
for h in (1..sr_hopcount).rev() {
|
||||
// Get blob to encrypt for next hop
|
||||
blob_data = {
|
||||
// RouteHop
|
||||
let mut rh_message = ::capnp::message::Builder::new_default();
|
||||
let mut rh_builder = rh_message.init_root::<veilid_capnp::route_hop::Builder>();
|
||||
let mut di_builder = rh_builder.reborrow().init_dial_info();
|
||||
encode_node_dial_info_single(&safety_route.hops[h].dial_info, &mut di_builder)?;
|
||||
// RouteHopData
|
||||
let mut rhd_builder = rh_builder.init_next_hop();
|
||||
// Add the nonce
|
||||
let mut rhd_nonce = rhd_builder.reborrow().init_nonce();
|
||||
encode_nonce(&nonce, &mut rhd_nonce);
|
||||
// Encrypt the previous blob ENC(nonce, DH(PKhop,SKsr))
|
||||
let dh_secret = self
|
||||
.crypto
|
||||
.cached_dh(
|
||||
&safety_route.hops[h].dial_info.node_id.key,
|
||||
&safety_route.secret_key,
|
||||
)
|
||||
.map_err(map_error_internal!("dh failed"))?;
|
||||
let enc_msg_data =
|
||||
Crypto::encrypt(blob_data.as_slice(), &nonce, &dh_secret, None)
|
||||
.map_err(map_error_internal!("encryption failed"))?;
|
||||
|
||||
rhd_builder.set_blob(enc_msg_data.as_slice());
|
||||
let mut blob_data = builder_to_vec(rh_message)?;
|
||||
|
||||
// append the route hop tag so we know how to decode it later
|
||||
blob_data.push(0u8);
|
||||
blob_data
|
||||
};
|
||||
// Make another nonce for the next hop
|
||||
nonce = Crypto::get_random_nonce();
|
||||
}
|
||||
|
||||
// Encode first RouteHopData
|
||||
let mut first_rhd_builder = hops_builder.init_data();
|
||||
let mut first_rhd_nonce = first_rhd_builder.reborrow().init_nonce();
|
||||
encode_nonce(&nonce, &mut first_rhd_nonce);
|
||||
let dh_secret = self
|
||||
.crypto
|
||||
.cached_dh(
|
||||
&safety_route.hops[0].dial_info.node_id.key,
|
||||
&safety_route.secret_key,
|
||||
)
|
||||
.map_err(map_error_internal!("dh failed"))?;
|
||||
let enc_msg_data = Crypto::encrypt(blob_data.as_slice(), &nonce, &dh_secret, None)
|
||||
.map_err(map_error_internal!("encryption failed"))?;
|
||||
|
||||
first_rhd_builder.set_blob(enc_msg_data.as_slice());
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// Wrap an operation inside a route
|
||||
pub(super) fn wrap_with_route<'a>(
|
||||
&self,
|
||||
safety_route: Option<&SafetyRouteSpec>,
|
||||
private_route: veilid_capnp::private_route::Reader<'a>,
|
||||
message_data: Vec<u8>,
|
||||
) -> Result<Vec<u8>, RPCError> {
|
||||
// Get stuff before we lock inner
|
||||
let op_id = self.get_next_op_id();
|
||||
// Encrypt routed operation
|
||||
let nonce = Crypto::get_random_nonce();
|
||||
let pr_pk_reader = private_route
|
||||
.get_public_key()
|
||||
.map_err(map_error_internal!("public key is invalid"))?;
|
||||
let pr_pk = decode_public_key(&pr_pk_reader);
|
||||
let stub_safety_route = SafetyRouteSpec::new();
|
||||
let sr = safety_route.unwrap_or(&stub_safety_route);
|
||||
let dh_secret = self
|
||||
.crypto
|
||||
.cached_dh(&pr_pk, &sr.secret_key)
|
||||
.map_err(map_error_internal!("dh failed"))?;
|
||||
let enc_msg_data = Crypto::encrypt(&message_data, &nonce, &dh_secret, None)
|
||||
.map_err(map_error_internal!("encryption failed"))?;
|
||||
|
||||
// Prepare route operation
|
||||
let route_msg = {
|
||||
let mut route_msg = ::capnp::message::Builder::new_default();
|
||||
let mut route_operation = route_msg.init_root::<veilid_capnp::operation::Builder>();
|
||||
|
||||
// Doesn't matter what this op id because there's no answer
|
||||
// but it shouldn't conflict with any other op id either
|
||||
route_operation.set_op_id(op_id);
|
||||
|
||||
// Answers don't get a 'respond'
|
||||
let mut respond_to = route_operation.reborrow().init_respond_to();
|
||||
respond_to.set_none(());
|
||||
|
||||
// Set up 'route' operation
|
||||
let mut route = route_operation.reborrow().init_detail().init_route();
|
||||
|
||||
// Set the safety route we've constructed
|
||||
let mut msg_sr = route.reborrow().init_safety_route();
|
||||
self.encode_safety_route(sr, private_route, &mut msg_sr)?;
|
||||
|
||||
// Put in the encrypted operation we're routing
|
||||
let mut msg_operation = route.init_operation();
|
||||
msg_operation.reborrow().init_signatures(0);
|
||||
let mut route_nonce = msg_operation.reborrow().init_nonce();
|
||||
encode_nonce(&nonce, &mut route_nonce);
|
||||
let data = msg_operation.reborrow().init_data(
|
||||
enc_msg_data
|
||||
.len()
|
||||
.try_into()
|
||||
.map_err(map_error_internal!("data too large"))?,
|
||||
);
|
||||
data.copy_from_slice(enc_msg_data.as_slice());
|
||||
|
||||
route_msg
|
||||
};
|
||||
|
||||
// Convert message to bytes and return it
|
||||
let out = builder_to_vec(route_msg)?;
|
||||
Ok(out)
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user