|
| 1 | +// an example of echo server with current code |
| 2 | +// |
| 3 | +#[macro_use] |
| 4 | +extern crate log; |
| 5 | + |
| 6 | +use futures::*; |
| 7 | +use futures::sync::mpsc; |
| 8 | +use hex::FromHex; |
| 9 | +use tokio::net::UdpSocket; |
| 10 | +use failure::{err_msg, Error}; |
| 11 | + |
| 12 | +use std::net::SocketAddr; |
| 13 | + |
| 14 | +use tox::toxcore::binary_io::*; |
| 15 | +use tox::toxcore::dht::server::Server; |
| 16 | +use tox::toxcore::dht::server_ext::ServerExt; |
| 17 | +use tox::toxcore::dht::packed_node::PackedNode; |
| 18 | +use tox::toxcore::dht::lan_discovery::LanDiscoverySender; |
| 19 | +use tox::toxcore::crypto_core::*; |
| 20 | +use tox::toxcore::friend_connection::FriendConnections; |
| 21 | +use tox::toxcore::friend_connection::packet::*; |
| 22 | +use tox::toxcore::net_crypto::{NetCrypto, NetCryptoNewArgs}; |
| 23 | +use tox::toxcore::onion::client::OnionClient; |
| 24 | +use tox::toxcore::tcp::client::Connections; |
| 25 | +use tox::toxcore::stats::Stats; |
| 26 | + |
| 27 | +const BOOTSTRAP_NODES: [(&str, &str); 9] = [ |
| 28 | + // Impyy |
| 29 | + ("1D5A5F2F5D6233058BF0259B09622FB40B482E4FA0931EB8FD3AB8E7BF7DAF6F", "198.98.51.198:33445"), |
| 30 | + // nurupo |
| 31 | + ("F404ABAA1C99A9D37D61AB54898F56793E1DEF8BD46B1038B9D822E8460FAB67", "67.215.253.85:33445"), |
| 32 | + // Manolis |
| 33 | + ("461FA3776EF0FA655F1A05477DF1B3B614F7D6B124F7DB1DD4FE3C08B03B640F", "130.133.110.14:33445"), |
| 34 | + // Busindre |
| 35 | + ("A179B09749AC826FF01F37A9613F6B57118AE014D4196A0E1105A98F93A54702", "205.185.116.116:33445"), |
| 36 | + // ray65536 |
| 37 | + ("8E7D0B859922EF569298B4D261A8CCB5FEA14FB91ED412A7603A585A25698832", "85.172.30.117:33445"), |
| 38 | + // fluke571 |
| 39 | + ("3CEE1F054081E7A011234883BC4FC39F661A55B73637A5AC293DDF1251D9432B", "194.249.212.109:33445"), |
| 40 | + // MAH69K |
| 41 | + ("DA4E4ED4B697F2E9B000EEFE3A34B554ACD3F45F5C96EAEA2516DD7FF9AF7B43", "185.25.116.107:33445"), |
| 42 | + // clearmartin |
| 43 | + ("CD133B521159541FB1D326DE9850F5E56A6C724B5B8E5EB5CD8D950408E95707", "46.101.197.175:443"), |
| 44 | + // tastytea |
| 45 | + ("2B2137E094F743AC8BD44652C55F41DFACC502F125E99E4FE24D40537489E32F", "5.189.176.217:5190"), |
| 46 | +]; |
| 47 | + |
| 48 | +const SELF_SK: &str = "1A5EC1D6C3F1FA720A313C01F432B6AE0D4649A5121964C9992DDF32871E8DFD"; |
| 49 | + |
| 50 | +const FRIEND_PK: &str = "3E6A06DA48D1AB98549AD76890770B704AE9116D8654FBCD35C9BF2DB9233E21"; |
| 51 | + |
| 52 | +/// Bind a UDP listener to the socket address. |
| 53 | +fn bind_socket(addr: SocketAddr) -> UdpSocket { |
| 54 | + let socket = UdpSocket::bind(&addr).expect("Failed to bind UDP socket"); |
| 55 | + socket.set_broadcast(true).expect("set_broadcast call failed"); |
| 56 | + if addr.is_ipv6() { |
| 57 | + socket.set_multicast_loop_v6(true).expect("set_multicast_loop_v6 call failed"); |
| 58 | + } |
| 59 | + socket |
| 60 | +} |
| 61 | + |
| 62 | +fn main() { |
| 63 | + env_logger::init(); |
| 64 | + |
| 65 | + let (dht_pk, dht_sk) = gen_keypair(); |
| 66 | + |
| 67 | + let real_sk_bytes: [u8; 32] = FromHex::from_hex(SELF_SK).unwrap(); |
| 68 | + let real_sk = SecretKey::from_slice(&real_sk_bytes).unwrap(); |
| 69 | + let real_pk = real_sk.public_key(); |
| 70 | + |
| 71 | + // Create a channel for server to communicate with network |
| 72 | + let (tx, rx) = mpsc::channel(32); |
| 73 | + |
| 74 | + let local_addr: SocketAddr = "0.0.0.0:33447".parse().unwrap(); // 0.0.0.0 for IPv4 |
| 75 | + // let local_addr: SocketAddr = "[::]:33445".parse().unwrap(); // [::] for IPv6 |
| 76 | + |
| 77 | + let socket = bind_socket(local_addr); |
| 78 | + let stats = Stats::new(); |
| 79 | + |
| 80 | + let lan_discovery_sender = LanDiscoverySender::new(tx.clone(), dht_pk, local_addr.is_ipv6()); |
| 81 | + |
| 82 | + let (tcp_incoming_tx, _tcp_incoming_rx) = mpsc::unbounded(); |
| 83 | + |
| 84 | + let mut dht_server = Server::new(tx.clone(), dht_pk, dht_sk.clone()); |
| 85 | + dht_server.enable_lan_discovery(true); |
| 86 | + dht_server.enable_ipv6_mode(local_addr.is_ipv6()); |
| 87 | + |
| 88 | + let tcp_connections = Connections::new(dht_pk, dht_sk.clone(), tcp_incoming_tx); |
| 89 | + let onion_client = OnionClient::new(dht_server.clone(), tcp_connections.clone(), real_sk.clone(), real_pk); |
| 90 | + |
| 91 | + let (lossless_tx, lossless_rx) = mpsc::unbounded(); |
| 92 | + let (lossy_tx, lossy_rx) = mpsc::unbounded(); |
| 93 | + |
| 94 | + let net_crypto = NetCrypto::new(NetCryptoNewArgs { |
| 95 | + udp_tx: tx, |
| 96 | + lossless_tx, |
| 97 | + lossy_tx, |
| 98 | + dht_pk, |
| 99 | + dht_sk, |
| 100 | + real_pk, |
| 101 | + real_sk: real_sk.clone(), |
| 102 | + precomputed_keys: dht_server.get_precomputed_keys(), |
| 103 | + }); |
| 104 | + |
| 105 | + dht_server.set_net_crypto(net_crypto.clone()); |
| 106 | + dht_server.set_onion_client(onion_client.clone()); |
| 107 | + |
| 108 | + let friend_connections = FriendConnections::new( |
| 109 | + real_sk, |
| 110 | + real_pk, |
| 111 | + dht_server.clone(), |
| 112 | + tcp_connections.clone(), |
| 113 | + onion_client.clone(), |
| 114 | + net_crypto.clone(), |
| 115 | + ); |
| 116 | + |
| 117 | + let friend_pk_bytes: [u8; 32] = FromHex::from_hex(FRIEND_PK).unwrap(); |
| 118 | + let friend_pk = PublicKey::from_slice(&friend_pk_bytes).unwrap(); |
| 119 | + |
| 120 | + friend_connections.add_friend(friend_pk); |
| 121 | + |
| 122 | + // Bootstrap from nodes |
| 123 | + for &(pk, saddr) in &BOOTSTRAP_NODES { |
| 124 | + // get PK bytes of the bootstrap node |
| 125 | + let bootstrap_pk_bytes: [u8; 32] = FromHex::from_hex(pk).unwrap(); |
| 126 | + // create PK from bytes |
| 127 | + let bootstrap_pk = PublicKey::from_slice(&bootstrap_pk_bytes).unwrap(); |
| 128 | + |
| 129 | + let node = PackedNode::new(saddr.parse().unwrap(), &bootstrap_pk); |
| 130 | + |
| 131 | + dht_server.add_initial_bootstrap(node); |
| 132 | + onion_client.add_path_node(node); |
| 133 | + } |
| 134 | + |
| 135 | + let net_crypto_c = net_crypto.clone(); |
| 136 | + let friend_connections_c = friend_connections.clone(); |
| 137 | + let lossless_future = lossless_rx |
| 138 | + .map_err(|()| unreachable!("rx can't fail")) |
| 139 | + .for_each(move |(pk, packet)| { |
| 140 | + match packet[0] { |
| 141 | + PACKET_ID_ALIVE => { |
| 142 | + friend_connections_c.handle_ping(pk); |
| 143 | + Box::new(future::ok(())) as Box<Future<Item = _, Error = _> + Send> |
| 144 | + }, |
| 145 | + PACKET_ID_SHARE_RELAYS => { |
| 146 | + match ShareRelays::from_bytes(&packet) { |
| 147 | + IResult::Done(_, share_relays) => |
| 148 | + Box::new(friend_connections_c.handle_share_relays(pk, share_relays) |
| 149 | + .map_err(Error::from)) |
| 150 | + as Box<Future<Item = _, Error = _> + Send>, |
| 151 | + _ => Box::new(future::err(err_msg("Failed to parse ShareRelays"))) |
| 152 | + } |
| 153 | + }, |
| 154 | + 0x18 => { // PACKET_ID_ONLINE |
| 155 | + let online_future = net_crypto_c.send_lossless(pk, vec![0x18]); |
| 156 | + let name_future = net_crypto_c.send_lossless(pk, b"\x30tox-rs".to_vec()); |
| 157 | + Box::new(online_future.join(name_future).map(|_| ()).map_err(Error::from)) |
| 158 | + }, |
| 159 | + 0x40 => { // PACKET_ID_CHAT_MESSAGE |
| 160 | + Box::new(net_crypto_c.send_lossless(pk, packet).map_err(Error::from)) |
| 161 | + }, |
| 162 | + _ => Box::new(future::ok(())), |
| 163 | + } |
| 164 | + }); |
| 165 | + |
| 166 | + let lossy_future = lossy_rx |
| 167 | + .map_err(|()| unreachable!("rx can't fail")) |
| 168 | + .for_each(|_| future::ok(())); |
| 169 | + |
| 170 | + let futures = vec![ |
| 171 | + Box::new(dht_server.run_socket(socket, rx, stats).map_err(Error::from)) as Box<Future<Item = _, Error = _> + Send>, |
| 172 | + Box::new(lan_discovery_sender.run().map_err(Error::from)), |
| 173 | + Box::new(tcp_connections.run().map_err(Error::from)), |
| 174 | + Box::new(onion_client.run().map_err(Error::from)), |
| 175 | + Box::new(net_crypto.run().map_err(Error::from)), |
| 176 | + Box::new(friend_connections.run().map_err(Error::from)), |
| 177 | + Box::new(lossless_future), |
| 178 | + Box::new(lossy_future), |
| 179 | + ]; |
| 180 | + |
| 181 | + let future = future::select_all(futures) |
| 182 | + .map(|_| ()) |
| 183 | + .map_err(|(e, _, _)| error!("Processing ended with error: {:?}", e)); |
| 184 | + |
| 185 | + info!("Running echo server on {}", local_addr); |
| 186 | + |
| 187 | + tokio::run(future); |
| 188 | +} |
0 commit comments