diff --git a/veilid-core/src/network_manager/mod.rs b/veilid-core/src/network_manager/mod.rs index b45e96c6..22616d2c 100644 --- a/veilid-core/src/network_manager/mod.rs +++ b/veilid-core/src/network_manager/mod.rs @@ -806,7 +806,7 @@ impl NetworkManager { // Do our half of the hole punch by sending an empty packet // Both sides will do this and then the receipt will get sent over the punched hole - network_result_try!( + let connection_descriptor = network_result_try!( self.net() .send_data_to_dial_info( hole_punch_dial_info_detail.dial_info.clone(), @@ -817,6 +817,9 @@ impl NetworkManager { // XXX: do we need a delay here? or another hole punch packet? + // Set the hole punch as our 'last connection' to ensure we return the receipt over the direct hole punch + peer_nr.set_last_connection(connection_descriptor, intf::get_timestamp()); + // Return the receipt using the same dial info send the receipt to it rpc.rpc_call_return_receipt(Destination::Direct(peer_nr), None, receipt) .await @@ -1178,6 +1181,8 @@ impl NetworkManager { // Do our half of the hole punch by sending an empty packet // Both sides will do this and then the receipt will get sent over the punched hole + // Don't bother storing the returned connection descriptor as the 'last connection' because the other side of the hole + // punch should come through and create a real 'last connection' for us if this succeeds network_result_try!( self.net() .send_data_to_dial_info(hole_punch_did.dial_info, Vec::new()) @@ -1294,7 +1299,12 @@ impl NetworkManager { } else { SendDataKind::GlobalDirect }; - network_result_try!(this.net().send_data_to_dial_info(dial_info, data).await?); + let connection_descriptor = network_result_try!( + this.net().send_data_to_dial_info(dial_info, data).await? + ); + // If we connected to this node directly, save off the last connection so we can use it again + node_ref.set_last_connection(connection_descriptor, intf::get_timestamp()); + Ok(NetworkResult::value(send_data_kind)) } ContactMethod::SignalReverse(relay_nr, target_node_ref) => { diff --git a/veilid-core/src/network_manager/native/mod.rs b/veilid-core/src/network_manager/native/mod.rs index 82629099..ccc233f2 100644 --- a/veilid-core/src/network_manager/native/mod.rs +++ b/veilid-core/src/network_manager/native/mod.rs @@ -493,13 +493,15 @@ impl Network { } // Send data directly to a dial info, possibly without knowing which node it is going to + // Returns a descriptor for the connection used to send the data #[instrument(level="trace", err, skip(self, data), fields(data.len = data.len()))] pub async fn send_data_to_dial_info( &self, dial_info: DialInfo, data: Vec, - ) -> EyreResult> { + ) -> EyreResult> { let data_len = data.len(); + let connection_descriptor; if dial_info.protocol_type() == ProtocolType::UDP { // Handle connectionless protocol let peer_socket_addr = dial_info.to_socket_addr(); @@ -507,10 +509,9 @@ impl Network { Some(ph) => ph, None => bail!("no appropriate UDP protocol handler for dial_info"), }; - let _ = network_result_try!(ph + connection_descriptor = network_result_try!(ph .send_message(data, peer_socket_addr) .await - .into_network_result() .wrap_err("failed to send data to dial info")?); } else { // Handle connection-oriented protocols @@ -527,13 +528,14 @@ impl Network { "failed to send", ))); } + connection_descriptor = conn.connection_descriptor(); } // Network accounting self.network_manager() .stats_packet_sent(dial_info.to_ip_addr(), data_len as u64); - Ok(NetworkResult::value(())) + Ok(NetworkResult::value(connection_descriptor)) } ///////////////////////////////////////////////////////////////// diff --git a/veilid-core/src/network_manager/native/protocol/udp.rs b/veilid-core/src/network_manager/native/protocol/udp.rs index 165144c0..a9599aed 100644 --- a/veilid-core/src/network_manager/native/protocol/udp.rs +++ b/veilid-core/src/network_manager/native/protocol/udp.rs @@ -42,7 +42,7 @@ impl RawUdpProtocolHandler { &self, data: Vec, socket_addr: SocketAddr, - ) -> io::Result> { + ) -> io::Result> { if data.len() > MAX_MESSAGE_SIZE { bail_io_error_other!("sending too large UDP message"); } @@ -56,7 +56,17 @@ impl RawUdpProtocolHandler { bail_io_error_other!("UDP partial send") } - Ok(NetworkResult::value(())) + let peer_addr = PeerAddress::new( + SocketAddress::from_socket_addr(socket_addr), + ProtocolType::UDP, + ); + let local_socket_addr = self.socket.local_addr()?; + let descriptor = ConnectionDescriptor::new( + peer_addr, + SocketAddress::from_socket_addr(local_socket_addr), + ); + + Ok(NetworkResult::value(descriptor)) } #[instrument(level = "trace", err)] diff --git a/veilid-core/src/network_manager/wasm/mod.rs b/veilid-core/src/network_manager/wasm/mod.rs index 77043bc2..16b168f7 100644 --- a/veilid-core/src/network_manager/wasm/mod.rs +++ b/veilid-core/src/network_manager/wasm/mod.rs @@ -191,7 +191,7 @@ impl Network { &self, dial_info: DialInfo, data: Vec, - ) -> EyreResult> { + ) -> EyreResult> { let data_len = data.len(); if dial_info.protocol_type() == ProtocolType::UDP { bail!("no support for UDP protocol"); @@ -201,18 +201,25 @@ impl Network { } // Handle connection-oriented protocols - let conn = self - .connection_manager() - .get_or_create_connection(None, dial_info.clone()) - .await?; + let conn = network_result_try!( + self.connection_manager() + .get_or_create_connection(Some(local_addr), dial_info.clone()) + .await? + ); - let res = conn.send_async(data).await; - if res.is_ok() { - // Network accounting - self.network_manager() - .stats_packet_sent(dial_info.to_ip_addr(), data_len as u64); + if let ConnectionHandleSendResult::NotSent(_) = conn.send_async(data).await { + return Ok(NetworkResult::NoConnection(io::Error::new( + io::ErrorKind::ConnectionReset, + "failed to send", + ))); } - res + let connection_descriptor = conn.connection_descriptor(); + + // Network accounting + self.network_manager() + .stats_packet_sent(dial_info.to_ip_addr(), data_len as u64); + + Ok(NetworkResult::value(connection_descriptor)) } ///////////////////////////////////////////////////////////////// diff --git a/veilid-core/src/routing_table/node_ref.rs b/veilid-core/src/routing_table/node_ref.rs index 55bce1ef..86e489fd 100644 --- a/veilid-core/src/routing_table/node_ref.rs +++ b/veilid-core/src/routing_table/node_ref.rs @@ -267,6 +267,10 @@ impl NodeRef { self.operate_mut(|e| e.clear_last_connection()) } + pub fn set_last_connection(&self, connection_descriptor: ConnectionDescriptor, ts: u64) { + self.operate_mut(|e| e.set_last_connection(connection_descriptor, ts)) + } + pub fn has_any_dial_info(&self) -> bool { self.operate(|e| { e.node_info()