@@ -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
136138impl 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