Skip to content

Commit 272e8ca

Browse files
authored
Merge pull request #158 from tox-rs/save
save or load dht daemon status
2 parents cafaa37 + 6b26f54 commit 272e8ca

File tree

6 files changed

+676
-1459
lines changed

6 files changed

+676
-1459
lines changed

src/toxcore/binary_io.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -122,9 +122,9 @@ macro_rules! encode_decode_test (
122122
#[test]
123123
fn $test() {
124124
let value = $value;
125-
let mut buf = [0; 1024];
125+
let mut buf = [0; 1024 * 1024];
126126
let (_, size) = value.to_bytes((&mut buf, 0)).unwrap();
127-
assert!(size <= 1024);
127+
assert!(size <= 1024 * 1024);
128128
let (rest, decoded_value) = FromBytes::from_bytes(&buf[..size]).unwrap();
129129
// this helps compiler to infer type of decoded_value
130130
// i.e. it means that decoded_value has the same type as value

src/toxcore/dht/daemon_state.rs

Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
/*
2+
Copyright (C) 2013 Tox project All Rights Reserved.
3+
Copyright © 2018 Namsoo CHO <[email protected]>
4+
5+
This file is part of Tox.
6+
7+
Tox is libre software: you can redistribute it and/or modify
8+
it under the terms of the GNU General Public License as published by
9+
the Free Software Foundation, either version 3 of the License, or
10+
(at your option) any later version.
11+
12+
Tox is distributed in the hope that it will be useful,
13+
but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15+
GNU General Public License for more details.
16+
17+
You should have received a copy of the GNU General Public License
18+
along with Tox. If not, see <http://www.gnu.org/licenses/>.
19+
*/
20+
21+
22+
/*!
23+
Serialize or deserialize states of tox daemon.
24+
When toxcore starts, it deserializes states from serialized file.
25+
Toxcore daemon may serialize its states to file with some interval.
26+
*/
27+
28+
use std::io::{Error, ErrorKind};
29+
30+
use futures::{future, Stream, stream};
31+
32+
use toxcore::dht::server::*;
33+
use toxcore::dht::packed_node::*;
34+
use toxcore::dht::server::client::*;
35+
use toxcore::state_format::old::*;
36+
use toxcore::binary_io::*;
37+
use toxcore::io_tokio::*;
38+
use toxcore::dht::kbucket::*;
39+
40+
/// serialize or deserialize states of DHT close lists
41+
#[derive(Clone, Debug)]
42+
pub struct DaemonState;
43+
44+
// close list has DhtNode, but when we access it with iter(), DhtNode is reformed to PackedNode
45+
const DHT_STATE_BUFFER_SIZE: usize =
46+
// Bucket size
47+
(
48+
// PackedNode size
49+
(
50+
32 + // PK size
51+
19 // SocketAddr maximum size
52+
) * BUCKET_DEFAULT_SIZE // num of DhtNodes per Bucket : 8
53+
) * KBUCKET_MAX_ENTRIES as usize; // 255
54+
55+
impl DaemonState {
56+
/// serialize DHT states, old means that the format of seriaization is old version
57+
pub fn serialize_old(server: &Server) -> Vec<u8> {
58+
let nodes = server.close_nodes.read().iter() // DhtNode is reformed to PackedNode through iter()
59+
.map(|node| node)
60+
.collect::<Vec<PackedNode>>();
61+
62+
let mut buf = [0u8; DHT_STATE_BUFFER_SIZE];
63+
let (_, buf_len) = DhtState(nodes).to_bytes((&mut buf, 0)).expect("DhtState(nodes).to_bytes has failed");
64+
65+
buf[..buf_len].to_vec()
66+
}
67+
68+
/// deserialize DHT close list and then re-setup close list, old means that the format of deserialization is old version
69+
pub fn deserialize_old(server: &Server, serialized_data: Vec<u8>) -> IoFuture<()> {
70+
let nodes = match DhtState::from_bytes(&serialized_data) {
71+
IResult::Done(_, DhtState(nodes)) => nodes,
72+
e => return Box::new(
73+
future::err(
74+
Error::new(ErrorKind::Other, format!("Can't deserialize DHT states from serialized bytes {:?}", e))
75+
)
76+
),
77+
};
78+
79+
let mut ping_map = server.ping_map.write();
80+
let nodes_sender = nodes.iter()
81+
.map(|node| {
82+
let client = ping_map.entry(node.pk).or_insert_with(PingData::new);
83+
84+
server.send_nodes_req(*node, server.pk, client)
85+
});
86+
87+
let nodes_stream = stream::futures_unordered(nodes_sender).then(|_| Ok(()));
88+
Box::new(nodes_stream.for_each(|()| Ok(())))
89+
}
90+
}
91+
92+
#[cfg(test)]
93+
mod tests {
94+
use super::*;
95+
96+
use toxcore::crypto_core::*;
97+
use toxcore::dht::packet::*;
98+
99+
use futures::sync::mpsc;
100+
use std::net::SocketAddr;
101+
use futures::Future;
102+
103+
macro_rules! unpack {
104+
($variable:expr, $variant:path) => (
105+
match $variable {
106+
$variant(inner) => inner,
107+
other => panic!("Expected {} but got {:?}", stringify!($variant), other),
108+
}
109+
)
110+
}
111+
112+
#[test]
113+
fn daemon_state_serialize_deserialize_test() {
114+
let (pk, sk) = gen_keypair();
115+
let (tx, rx) = mpsc::unbounded::<(DhtPacket, SocketAddr)>();
116+
let alice = Server::new(tx, pk, sk);
117+
118+
let addr_org = "1.2.3.4:1234".parse().unwrap();
119+
let pk_org = gen_keypair().0;
120+
let pn = PackedNode { pk: pk_org, saddr: addr_org };
121+
alice.close_nodes.write().try_add(&pn);
122+
123+
let serialized_vec = DaemonState::serialize_old(&alice);
124+
DaemonState::deserialize_old(&alice, serialized_vec).wait().unwrap();
125+
126+
let (received, _rx) = rx.into_future().wait().unwrap();
127+
let (packet, addr_to_send) = received.unwrap();
128+
129+
assert_eq!(addr_to_send, addr_org);
130+
131+
let sending_packet = unpack!(packet, DhtPacket::NodesRequest);
132+
133+
assert_eq!(sending_packet.pk, pk);
134+
135+
// test with incompleted serialized data
136+
let serialized_vec = DaemonState::serialize_old(&alice);
137+
let serialized_len = serialized_vec.len();
138+
assert!(DaemonState::deserialize_old(&alice, serialized_vec[..serialized_len - 1].to_vec()).wait().is_err());
139+
140+
// test with empty close list
141+
alice.close_nodes.write().remove(&pk_org);
142+
let serialized_vec = DaemonState::serialize_old(&alice);
143+
assert!(DaemonState::deserialize_old(&alice, serialized_vec).wait().is_ok());
144+
}
145+
}

src/toxcore/dht/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,3 +29,4 @@ pub mod codec;
2929
pub mod server;
3030
pub mod dht_friend;
3131
pub mod dht_node;
32+
pub mod daemon_state;

src/toxcore/dht/server/mod.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -107,16 +107,16 @@ pub struct Server {
107107
pub tx: Tx,
108108
/// option for hole punching
109109
pub is_hole_punching_enabled: bool,
110-
// store ping object which has sent request packet to peer
111-
ping_map: Arc<RwLock<HashMap<PublicKey, PingData>>>,
112-
// Close List (contains nodes close to own DHT PK)
113-
close_nodes: Arc<RwLock<Kbucket>>,
110+
/// store ping object which has sent request packet to peer
111+
pub ping_map: Arc<RwLock<HashMap<PublicKey, PingData>>>,
112+
/// Close List (contains nodes close to own DHT PK)
113+
pub close_nodes: Arc<RwLock<Kbucket>>,
114114
// symmetric key used for onion return encryption
115115
onion_symmetric_key: Arc<RwLock<secretbox::Key>>,
116116
// onion announce struct to handle onion packets
117117
onion_announce: Arc<RwLock<OnionAnnounce>>,
118-
// friends vector of dht node
119-
friends: Arc<RwLock<Vec<DhtFriend>>>,
118+
/// friends vector of dht node
119+
pub friends: Arc<RwLock<Vec<DhtFriend>>>,
120120
// nodes vector for bootstrap
121121
bootstrap_nodes: Arc<RwLock<Bucket>>,
122122
// count for sending NodesRequest to random node which is in close node

src/toxcore/state_format/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,4 +31,4 @@ https://zetok.github.io/tox-spec/#state-format
3131

3232

3333
// FIXME: use new dht code instead of old
34-
// pub mod old;
34+
pub mod old;

0 commit comments

Comments
 (0)