Skip to content

Commit de5e84d

Browse files
committed
feat(onion_client): stop looking for a friend when he becomes connected
1 parent ae2ed10 commit de5e84d

File tree

2 files changed

+134
-2
lines changed

2 files changed

+134
-2
lines changed

src/toxcore/friend_connection/mod.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -274,6 +274,7 @@ impl FriendConnections {
274274

275275
/// Handle the stream of connection statuses.
276276
fn handle_connection_status(&self, connnection_status_rx: mpsc::UnboundedReceiver<(PublicKey, bool)>) -> impl Future<Item = (), Error = RunError> + Send {
277+
let onion_client = self.onion_client.clone();
277278
let friends = self.friends.clone();
278279
let connection_status_tx = self.connection_status_tx.clone();
279280
connnection_status_rx
@@ -293,6 +294,7 @@ impl FriendConnections {
293294

294295
if status != friend.connected {
295296
friend.connected = status;
297+
onion_client.set_friend_connected(real_pk, status);
296298
if let Some(ref connection_status_tx) = *connection_status_tx.read() {
297299
return Either::A(send_to(connection_status_tx, (real_pk, status))
298300
.map_err(|e| e.context(RunErrorKind::SendToConnectionStatus).into()));
@@ -668,6 +670,7 @@ mod tests {
668670
friend.ping_sent_time = Some(now);
669671
friend.share_relays_time = Some(now);
670672
friend_connections.friends.write().insert(friend_pk, friend);
673+
friend_connections.onion_client.add_friend(friend_pk);
671674

672675
let (connnection_status_tx, connnection_status_rx) = mpsc::unbounded();
673676
send_to(&connnection_status_tx, (friend_pk, true)).wait().unwrap();
@@ -685,6 +688,8 @@ mod tests {
685688
assert_eq!(friend.ping_received_time, Some(now));
686689
assert!(friend.ping_sent_time.is_none());
687690
assert!(friend.share_relays_time.is_none());
691+
692+
assert!(friend_connections.onion_client.is_friend_connected(&friend_pk));
688693
}
689694

690695
#[test]
@@ -699,6 +704,8 @@ mod tests {
699704
friend.dht_pk_time = Some(now);
700705
friend.connected = true;
701706
friend_connections.friends.write().insert(friend_pk, friend);
707+
friend_connections.onion_client.add_friend(friend_pk);
708+
friend_connections.onion_client.set_friend_connected(friend_pk, true);
702709

703710
let (connnection_status_tx, connnection_status_rx) = mpsc::unbounded();
704711
send_to(&connnection_status_tx, (friend_pk, false)).wait().unwrap();
@@ -714,6 +721,8 @@ mod tests {
714721
let friend = &friend_connections.friends.read()[&friend_pk];
715722
assert!(!friend.connected);
716723
assert_eq!(friend.dht_pk_time, Some(now));
724+
725+
assert!(!friend_connections.onion_client.is_friend_connected(&friend_pk));
717726
}
718727

719728
#[test]

src/toxcore/onion/client/mod.rs

Lines changed: 125 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,8 @@ struct OnionFriend {
131131
search_count: u32,
132132
/// Time when this friend was seen online last time
133133
last_seen: Option<Instant>,
134+
/// Whether we connected to this friend.
135+
connected: bool,
134136
}
135137

136138
impl OnionFriend {
@@ -148,6 +150,7 @@ impl OnionFriend {
148150
last_dht_pk_dht_sent: None,
149151
search_count: 0,
150152
last_seen: None,
153+
connected: false,
151154
}
152155
}
153156
}
@@ -563,6 +566,23 @@ impl OnionClient {
563566
state.friends.remove(&real_pk);
564567
}
565568

569+
/// Set connection status of a friend. If he's connected we can stop looking
570+
/// for his DHT `PublicKey`.
571+
pub fn set_friend_connected(&self, real_pk: PublicKey, connected: bool) {
572+
let mut state = self.state.lock();
573+
574+
if let Some(friend) = state.friends.get_mut(&real_pk) {
575+
if friend.connected && !connected {
576+
friend.last_seen = Some(clock_now());
577+
friend.search_count = 0;
578+
// reset no_reply for the case when a friend will try to connect
579+
// from a different device with different clock
580+
friend.last_no_reply = 0;
581+
}
582+
friend.connected = connected;
583+
}
584+
}
585+
566586
/// Set friend's DHT `PublicKey` when it gets known somewhere else.
567587
pub fn set_friend_dht_pk(&self, real_pk: PublicKey, dht_pk: PublicKey) {
568588
let mut state = self.state.lock();
@@ -780,7 +800,9 @@ impl OnionClient {
780800
let mut packets = Vec::new();
781801

782802
for friend in state.friends.values_mut() {
783-
// TODO: if is_online
803+
if friend.connected {
804+
continue;
805+
}
784806

785807
let announce_packet_data = AnnouncePacketData {
786808
packet_sk: &friend.temporary_sk,
@@ -870,6 +892,10 @@ mod tests {
870892
pub fn friend_dht_pk(&self, pk: &PublicKey) -> Option<PublicKey> {
871893
self.state.lock().friends.get(pk).and_then(|friend| friend.dht_pk)
872894
}
895+
896+
pub fn is_friend_connected(&self, pk: &PublicKey) -> bool {
897+
self.state.lock().friends.get(pk).map_or(false, |friend| friend.connected)
898+
}
873899
}
874900

875901
fn unpack_onion_packet(packet: OnionRequest0, saddr: SocketAddr, key_by_addr: &HashMap<SocketAddr, SecretKey>) -> OnionRequest2Payload {
@@ -1116,6 +1142,39 @@ mod tests {
11161142
assert!(!onion_client.state.lock().friends.contains_key(&friend_pk));
11171143
}
11181144

1145+
#[test]
1146+
fn set_friend_connected() {
1147+
let (dht_pk, dht_sk) = gen_keypair();
1148+
let (real_pk, real_sk) = gen_keypair();
1149+
let (udp_tx, _udp_rx) = mpsc::channel(1);
1150+
let (tcp_incoming_tx, _tcp_incoming_rx) = mpsc::unbounded();
1151+
let dht = DhtServer::new(udp_tx, dht_pk, dht_sk.clone());
1152+
let tcp_connections = TcpConnections::new(dht_pk, dht_sk, tcp_incoming_tx);
1153+
let onion_client = OnionClient::new(dht, tcp_connections, real_sk, real_pk);
1154+
1155+
let (friend_pk, _friend_sk) = gen_keypair();
1156+
onion_client.add_friend(friend_pk);
1157+
1158+
onion_client.set_friend_connected(friend_pk, true);
1159+
1160+
let state = onion_client.state.lock();
1161+
assert!(state.friends[&friend_pk].connected);
1162+
drop(state);
1163+
1164+
let now = Instant::now();
1165+
let mut enter = tokio_executor::enter().unwrap();
1166+
let clock = Clock::new_with_now(ConstNow(now));
1167+
1168+
with_default(&clock, &mut enter, |_| {
1169+
onion_client.set_friend_connected(friend_pk, false);
1170+
});
1171+
1172+
let state = onion_client.state.lock();
1173+
let friend = &state.friends[&friend_pk];
1174+
assert!(!friend.connected);
1175+
assert_eq!(friend.last_seen, Some(now));
1176+
}
1177+
11191178
#[test]
11201179
fn set_friend_dht_pk() {
11211180
let (dht_pk, dht_sk) = gen_keypair();
@@ -1961,7 +2020,7 @@ mod tests {
19612020
state.friends.insert(friend_pk, friend);
19622021

19632022
let mut enter = tokio_executor::enter().unwrap();
1964-
// time when entry is timed out
2023+
// time when announce packet should be sent
19652024
let clock = Clock::new_with_now(ConstNow(
19662025
now + Duration::from_secs(ANNOUNCE_INTERVAL_NOT_ANNOUNCED + 1)
19672026
));
@@ -1989,6 +2048,70 @@ mod tests {
19892048
}
19902049
}
19912050

2051+
#[test]
2052+
fn friends_loop_ignore_online() {
2053+
let (dht_pk, dht_sk) = gen_keypair();
2054+
let (real_pk, real_sk) = gen_keypair();
2055+
let (udp_tx, udp_rx) = mpsc::channel(MAX_ONION_FRIEND_NODES as usize);
2056+
let (tcp_incoming_tx, _tcp_incoming_rx) = mpsc::unbounded();
2057+
let dht = DhtServer::new(udp_tx, dht_pk, dht_sk.clone());
2058+
let tcp_connections = TcpConnections::new(dht_pk, dht_sk, tcp_incoming_tx);
2059+
let onion_client = OnionClient::new(dht, tcp_connections, real_sk.clone(), real_pk);
2060+
2061+
let mut state = onion_client.state.lock();
2062+
2063+
let (friend_pk, _friend_sk) = gen_keypair();
2064+
let mut friend = OnionFriend::new(friend_pk);
2065+
friend.connected = true;
2066+
2067+
let addr = "127.0.0.1".parse().unwrap();
2068+
for i in 0 .. 3 {
2069+
let saddr = SocketAddr::new(addr, 12346 + i);
2070+
let (pk, _sk) = gen_keypair();
2071+
let node = PackedNode::new(saddr, &pk);
2072+
state.paths_pool.path_nodes.put(node);
2073+
}
2074+
2075+
let now = Instant::now();
2076+
2077+
for i in 0 .. MAX_ONION_FRIEND_NODES {
2078+
let saddr = SocketAddr::new(addr, 23456 + u16::from(i));
2079+
let path = state.paths_pool.random_path(false).unwrap();
2080+
let (node_pk, _node_sk) = gen_keypair();
2081+
let node = OnionNode {
2082+
pk: node_pk,
2083+
saddr,
2084+
path_id: path.id(),
2085+
ping_id: None,
2086+
data_pk: None,
2087+
unsuccessful_pings: 0,
2088+
added_time: now,
2089+
ping_time: now,
2090+
response_time: now,
2091+
announce_status: AnnounceStatus::Failed,
2092+
};
2093+
assert!(friend.close_nodes.try_add(&real_pk, node, true));
2094+
}
2095+
2096+
state.friends.insert(friend_pk, friend);
2097+
2098+
let mut enter = tokio_executor::enter().unwrap();
2099+
// time when announce packet should be sent
2100+
let clock = Clock::new_with_now(ConstNow(
2101+
now + Duration::from_secs(ANNOUNCE_INTERVAL_NOT_ANNOUNCED + 1)
2102+
));
2103+
2104+
with_default(&clock, &mut enter, |_| {
2105+
onion_client.friends_loop(&mut state).wait().unwrap();
2106+
});
2107+
2108+
// Necessary to drop tx so that rx.collect() can be finished
2109+
drop(state);
2110+
drop(onion_client);
2111+
2112+
assert!(udp_rx.collect().wait().unwrap().is_empty());
2113+
}
2114+
19922115
#[test]
19932116
fn send_dht_pk_onion() {
19942117
let (dht_pk, dht_sk) = gen_keypair();

0 commit comments

Comments
 (0)