├── .cargo └── config.toml ├── .github ├── dependabot.yml └── workflows │ └── main.yml ├── .gitignore ├── Cargo.toml ├── LICENSE-APACHE ├── LICENSE-AW ├── LICENSE-MIT ├── README.md ├── chamomile ├── Cargo.toml ├── LICENSE-APACHE ├── LICENSE-MIT ├── README.md ├── examples │ ├── own.rs │ ├── permissioned.rs │ ├── permissionless.rs │ └── relay.rs └── src │ ├── buffer.rs │ ├── config.rs │ ├── global.rs │ ├── hole_punching.rs │ ├── kad.rs │ ├── lan.rs │ ├── lib.rs │ ├── peer_list.rs │ ├── primitives.rs │ ├── server.rs │ ├── session.rs │ ├── session_key.rs │ ├── transports.rs │ └── transports │ ├── quic.rs │ ├── rtp.rs │ ├── tcp.rs │ ├── udp.rs │ └── udt.rs └── types ├── Cargo.toml ├── README.md └── src ├── key.rs ├── lib.rs ├── message.rs ├── peer.rs └── types.rs /.cargo/config.toml: -------------------------------------------------------------------------------- 1 | [build] 2 | rustflags = ["--cfg", "tokio_unstable"] -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "cargo" # See documentation for possible values 4 | directory: "/" # Location of package manifests 5 | target-branch: "main" 6 | schedule: 7 | interval: "daily" 8 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: Main 2 | 3 | on: 4 | pull_request: 5 | branches: 6 | - main 7 | workflow_dispatch: 8 | 9 | env: 10 | CARGO_TERM_COLOR: always 11 | 12 | jobs: 13 | build: 14 | runs-on: ubuntu-latest 15 | 16 | steps: 17 | - uses: actions/checkout@v2 18 | 19 | - name: Setup | Rust 20 | uses: ATiltedTree/setup-rust@v1 21 | with: 22 | rust-version: stable 23 | 24 | - run: cargo test 25 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | **/*.rs.bk 3 | Cargo.lock 4 | p2p 5 | .data 6 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = [ 3 | "chamomile", 4 | "types", 5 | ] 6 | resolver = "2" 7 | 8 | [workspace.package] 9 | version = "0.11.2" 10 | edition = "2024" 11 | authors = ["Dev "] 12 | readme = "README.md" 13 | repository = "https://github.com/postsilicondev/chamomile" 14 | categories = ["network-programming", "web-programming"] 15 | keywords = ["distributed", "blockchain", "p2p", "libp2p", "peer-to-peer"] 16 | description = "Another P2P Library. Support IoT devices." 17 | license = "MIT/Apache-2.0" 18 | 19 | [workspace.dependencies] 20 | chamomile_types = { version = "0.11", path = "./types" } 21 | aes-gcm = "0.10" 22 | bit-vec = "0.8" 23 | bytes = {version = "1.8", features = ["serde"] } 24 | console-subscriber = "0.4" 25 | hex = "0.4" 26 | quinn = "0.10" 27 | quinn-proto = "0.10" 28 | rand_chacha = "0.3" 29 | rand_core = "0.6" 30 | rcgen = "0.11" 31 | rustls = { version = "0.21", features = ["dangerous_configuration"] } 32 | secp256k1 = { version = "0.30", features = ["recovery", "rand"] } 33 | serde = { version = "1.0", features = ["derive"] } 34 | sha3 = "0.10" 35 | socket2 = "0.5" 36 | structopt = "0.3" 37 | thiserror = "2.0" 38 | tracing = "0.1" 39 | tracing-subscriber = "0.3" 40 | tokio = { version = "1", features = ["full"] } 41 | webpki = "0.22" 42 | zeroize = { version = "1", features = ["zeroize_derive"] } 43 | -------------------------------------------------------------------------------- /LICENSE-APACHE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright (c) 2019-NOW Sun (Buy me a Tea) 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /LICENSE-AW: -------------------------------------------------------------------------------- 1 | Anti-War LICENSE 2 | 3 | Version 0.1, February 2022 4 | 5 | THIS IS AN EXTENSION OPEN SOURCE LICENSE 6 | 7 | All those who support start a war are banned to 8 | use, copy, modify, merge, publish, distribute, 9 | sublicense, and/or sell copies of the Software. 10 | 11 | This software only targets the aggressor, 12 | not the victimized party. 13 | -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Copyright (c) 2019-NOW Sun (Buy me a Tea) 2 | 3 | Permission is hereby granted, free of charge, to any 4 | person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the 6 | Software without restriction, including without 7 | limitation the rights to use, copy, modify, merge, 8 | publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software 10 | is furnished to do so, subject to the following 11 | conditions: 12 | 13 | The above copyright notice and this permission notice 14 | shall be included in all copies or substantial portions 15 | of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 18 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 19 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 20 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 21 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 22 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 23 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 24 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 | DEALINGS IN THE SOFTWARE. 26 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![crate](https://img.shields.io/badge/crates.io-v0.11.2-green.svg)](https://crates.io/crates/chamomile) [![doc](https://img.shields.io/badge/docs.rs-v0.11.2-blue.svg)](https://docs.rs/chamomile) 2 | 3 | # Chamomile 4 | *Build a robust stable connection on p2p network* 5 | 6 | ## features 7 | - Support build a robust stable connection between two peers on the p2p network. 8 | - Support permissionless network. 9 | - Support permissioned network (distributed network). 10 | - DHT-based & Relay connection. 11 | - Diff transports: QUIC(*default*) / TCP / UDP-Based Special Protocol. 12 | - Multiple transports connecting at same runtime. 13 | 14 | ## Simple test. 15 | - A: `cargo run --example permissionless 127.0.0.1:8000` 16 | - B: `cargo run --example permissionless 127.0.0.1:8001 127.0.0.1:8000` 17 | - C: `cargo run --example permissionless 127.0.0.1:8002 127.0.0.1:8000` 18 | 19 | If not support `127.0.0.1` binding, you can change to `0.0.0.0` and try again. 20 | 21 | ## Relay test. 22 | - A: `cargo run --example relay 192.168.xx.xx:8000` 23 | - this ip is your LAN address, it will do relay work. 24 | - B: `cargo run --example relay 127.0.0.1:8001 192.168.xx.xx:8000` 25 | - start waiting stable connected by relay. 26 | - C: `cargo run --example relay 127.0.0.1:8002 192.168.xx.xx:8000 XX..` 27 | - XX.. is above's B network `peer id` will connected it. 28 | - And if change B and C `127.0.0.1` to `0.0.0.0`, they will automatically connect after the handshake is successful, no longer need relay. 29 | 30 | ## Design point 31 | - Mobile phones, IoT devices, PC and servers are first-class citizens 32 | - Ability to adapt to the transmission and penetration of complex network environments 33 | - Support for springboard function, virtual connection with other nodes, build virtual DHT 34 | - Encrypted transmission and secure DHT protection 35 | - It can support all interconnections and single-center connections under the LAN, and can also support DHT in the public network environment 36 | - Automatically switch the connection according to the number of connections and the network environment 37 | - If Alice use QUIC, Bob use TCP, they can still connect and communicate with each other. 38 | 39 | ## License 40 | 41 | This project is licensed under either of 42 | 43 | * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or 44 | http://www.apache.org/licenses/LICENSE-2.0) 45 | * MIT license ([LICENSE-MIT](LICENSE-MIT) or 46 | http://opensource.org/licenses/MIT) 47 | * Anti-War license ([LICENSE-AW](LICENSE-AW) or 48 | https://github.com/sunhuachuang/AW-License) 49 | 50 | at your option. 51 | -------------------------------------------------------------------------------- /chamomile/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chamomile" 3 | version.workspace = true 4 | edition.workspace = true 5 | authors.workspace = true 6 | repository.workspace = true 7 | categories.workspace = true 8 | keywords.workspace = true 9 | description.workspace = true 10 | license.workspace = true 11 | 12 | [dependencies] 13 | chamomile_types.workspace = true 14 | aes-gcm.workspace = true 15 | bit-vec.workspace = true 16 | bytes.workspace = true 17 | quinn.workspace = true 18 | quinn-proto.workspace = true 19 | rand_chacha.workspace = true 20 | rcgen.workspace = true 21 | rustls.workspace = true 22 | serde.workspace = true 23 | socket2.workspace = true 24 | structopt.workspace = true 25 | thiserror.workspace = true 26 | tracing.workspace = true 27 | tokio.workspace = true 28 | webpki.workspace = true 29 | zeroize.workspace = true 30 | 31 | [dev-dependencies] 32 | console-subscriber.workspace = true 33 | tracing-subscriber.workspace = true 34 | -------------------------------------------------------------------------------- /chamomile/LICENSE-APACHE: -------------------------------------------------------------------------------- 1 | ../LICENSE-APACHE -------------------------------------------------------------------------------- /chamomile/LICENSE-MIT: -------------------------------------------------------------------------------- 1 | ../LICENSE-MIT -------------------------------------------------------------------------------- /chamomile/README.md: -------------------------------------------------------------------------------- 1 | ../README.md -------------------------------------------------------------------------------- /chamomile/examples/own.rs: -------------------------------------------------------------------------------- 1 | //! Test the own (same PeerId) message. 2 | //! Runing 3-node: 1 (relay - S), 2 (own - A, B) 3 | //! 1. Run S at 8000: `cargo run --example relay 192.168.xx.xx:8000` 4 | //! 2. Run A at 127.0.0.1:0: `cargo run --example own 192.168.xx.xx:8000` 5 | //! 3. Run B at 127.0.0.1:0: `cargo run --example own 192.168.xx.xx:8000` 6 | 7 | use chamomile::prelude::*; 8 | use chamomile_types::{key::secp256k1::rand::Rng, types::TransportType}; 9 | use rand_chacha::{rand_core::SeedableRng, ChaChaRng}; 10 | use std::{env::args, net::SocketAddr}; 11 | 12 | #[tokio::main] 13 | async fn main() { 14 | std::env::set_var("RUST_LOG", "debug"); 15 | tracing_subscriber::fmt() 16 | .with_level(true) 17 | .with_max_level(tracing::Level::DEBUG) 18 | .init(); 19 | 20 | let addr_str = args().nth(1).expect("missing realy"); 21 | let relay: SocketAddr = addr_str.parse().expect("invalid addr"); 22 | 23 | let mut rng = ChaChaRng::from_entropy(); 24 | let mut peer = Peer::socket("127.0.0.1:0".parse().unwrap()); 25 | peer.transport = TransportType::TCP; 26 | let mut config = Config::default(peer); 27 | config.permission = true; 28 | config.db_dir = std::path::PathBuf::from(format!(".data/own/{}", rng.gen::())); 29 | 30 | // default key to test own. 31 | let key = Key::from_db_bytes(&[ 32 | 0, 72, 137, 44, 19, 236, 242, 211, 157, 163, 190, 217, 116, 14, 149, 254, 211, 242, 248, 33 | 101, 191, 114, 185, 88, 249, 177, 115, 181, 251, 9, 10, 71, 13, 236, 8, 166, 64, 201, 101, 34 | 183, 186, 156, 138, 166, 75, 253, 158, 211, 124, 155, 152, 89, 33, 8, 72, 160, 108, 248, 35 | 205, 76, 100, 75, 133, 247, 202, 36 | ]) 37 | .unwrap(); 38 | 39 | let (peer_id, send, mut recv) = start_with_key(config, key).await.unwrap(); 40 | println!("peer id: {}", peer_id.to_hex()); 41 | let mut relay = Peer::socket(relay); 42 | relay.transport = TransportType::QUIC; 43 | let _ = send.send(SendMessage::Connect(relay)).await; 44 | 45 | while let Some(message) = recv.recv().await { 46 | match message { 47 | ReceiveMessage::OwnConnect(peer) => { 48 | println!("Own connected, assist: {}", peer.assist.to_hex()); 49 | let _ = send.send(SendMessage::OwnEvent(vec![1, 2, 3, 4])).await; 50 | } 51 | ReceiveMessage::OwnEvent(_pid, data) => { 52 | println!("Receive data: {:?}", data); 53 | } 54 | ReceiveMessage::OwnLeave(peer) => { 55 | println!("Own leaved, assist: {}", peer.assist.to_hex()); 56 | } 57 | ReceiveMessage::NetworkLost => { 58 | println!("Network lost..."); 59 | } 60 | _ => { 61 | panic!("Nerver here!!!") 62 | } 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /chamomile/examples/permissioned.rs: -------------------------------------------------------------------------------- 1 | //! Test the permissioned message. 2 | //! Runing 3-node: 1 (relay - S), 2 (stable - A, B) 3 | //! A: `cargo run --example permissioned 127.0.0.1:8000` 4 | //! B: `cargo run --example permissioned 127.0.0.1:8001 127.0.0.1:8000` 5 | //! C: `cargo run --example permissioned 127.0.0.1:8002 127.0.0.1:8000` 6 | 7 | use chamomile::prelude::{start, Config, Peer, ReceiveMessage, SendMessage}; 8 | use std::{env::args, net::SocketAddr}; 9 | 10 | #[tokio::main] 11 | async fn main() { 12 | std::env::set_var("RUST_LOG", "debug"); 13 | tracing_subscriber::fmt::init(); 14 | 15 | let addr_str = args().nth(1).expect("missing path"); 16 | let self_addr: SocketAddr = addr_str.parse().expect("invalid addr"); 17 | 18 | let mut config = Config::default(Peer::socket(self_addr)); 19 | config.permission = true; 20 | config.db_dir = std::path::PathBuf::from(format!(".data/permissioned/{}", addr_str)); 21 | 22 | let (peer_id, send, mut recv) = start(config).await.unwrap(); 23 | println!("peer id: {}", peer_id.to_hex()); 24 | 25 | if args().nth(2).is_some() { 26 | let remote_addr: SocketAddr = args().nth(2).unwrap().parse().expect("invalid addr"); 27 | println!("start connect to remote: {}", remote_addr); 28 | send.send(SendMessage::Connect(Peer::socket(remote_addr))) 29 | .await 30 | .expect("channel failure!"); 31 | } 32 | 33 | while let Some(message) = recv.recv().await { 34 | match message { 35 | ReceiveMessage::Data(peer_id, bytes) => { 36 | println!("Recv data from: {}, {:?}", peer_id.short_show(), bytes); 37 | } 38 | ReceiveMessage::StableConnect(peer, join_data) => { 39 | println!("Peer join: {:?}, join data: {:?}", peer, join_data); 40 | send.send(SendMessage::StableResult(0, peer, true, false, vec![1])) 41 | .await 42 | .expect("channel failure!"); 43 | } 44 | ReceiveMessage::StableResult(peer, is_ok, data) => { 45 | println!("Peer Join Result: {:?} {}, data: {:?}", peer, is_ok, data); 46 | } 47 | ReceiveMessage::ResultConnect(from, _data) => { 48 | println!("Recv Result Connect {:?}", from); 49 | } 50 | ReceiveMessage::StableLeave(peer) => { 51 | println!("Peer_leave: {:?}", peer); 52 | } 53 | ReceiveMessage::NetworkLost => { 54 | println!("No peers conneced.") 55 | } 56 | _ => { 57 | panic!("nerver here!"); 58 | } 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /chamomile/examples/permissionless.rs: -------------------------------------------------------------------------------- 1 | //! Test the permissionless message. 2 | //! Runing 3-node: 1 (relay - S), 2 (dht - A, B) 3 | //! A: `cargo run --example permissionless 127.0.0.1:8000` 4 | //! B: `cargo run --example permissionless 127.0.0.1:8001 127.0.0.1:8000` 5 | //! C: `cargo run --example permissionless 127.0.0.1:8002 127.0.0.1:8000` 6 | 7 | use chamomile::prelude::{start, Broadcast, Config, Peer, ReceiveMessage, SendMessage}; 8 | use std::{env::args, net::SocketAddr, time::Duration}; 9 | 10 | #[tokio::main] 11 | async fn main() { 12 | std::env::set_var("RUST_LOG", "debug"); 13 | 14 | //console_subscriber::init(); 15 | tracing_subscriber::fmt::init(); 16 | 17 | let addr_str = args().nth(1).expect("missing path"); 18 | let self_addr: SocketAddr = addr_str.parse().expect("invalid addr"); 19 | 20 | println!("START A PERMISSIONLESS PEER. socket: {}", self_addr); 21 | let peer = Peer::socket(self_addr); 22 | // let mut peer = Peer::socket(self_addr); 23 | // peer.transport = chamomile_types::types::TransportType::TCP; // DEBUG different transport. 24 | 25 | let mut config = Config::default(peer); 26 | config.permission = false; // Permissionless. 27 | config.only_stable_data = false; // Receive all peer's data. 28 | config.db_dir = std::path::PathBuf::from(format!(".data/permissionless/{}", addr_str)); 29 | 30 | let (peer_id, send, mut recv) = start(config).await.unwrap(); 31 | println!("peer id: {}", peer_id.to_hex()); 32 | 33 | if args().nth(2).is_some() { 34 | let remote_addr: SocketAddr = args().nth(2).unwrap().parse().expect("invalid addr"); 35 | println!("start DHT connect to remote: {}", remote_addr); 36 | let _ = send 37 | .send(SendMessage::Connect(Peer::socket(remote_addr))) 38 | .await; 39 | 40 | println!("sleep 3s and then broadcast..."); 41 | tokio::time::sleep(Duration::from_secs(2)).await; 42 | 43 | fn mod_reduce(mut i: u32) -> u8 { 44 | loop { 45 | if i > 255 { 46 | i = i - 255 47 | } else { 48 | break; 49 | } 50 | } 51 | i as u8 52 | } 53 | 54 | let mut bytes = vec![]; 55 | for i in 0..10u32 { 56 | bytes.push(mod_reduce(i)); 57 | } 58 | 59 | println!("Will send bytes: {}-{:?}", bytes.len(), &bytes); 60 | let _ = send 61 | .send(SendMessage::Broadcast(Broadcast::Gossip, bytes)) 62 | .await; 63 | 64 | // if send this will stop and close the network. 65 | //let _ = send.send(SendMessage::NetworkStop).await; 66 | } 67 | 68 | while let Some(message) = recv.recv().await { 69 | match message { 70 | ReceiveMessage::Data(remote_id, bytes) => { 71 | println!( 72 | "Recv permissionless data from: {}, {}-{:?}", 73 | remote_id.short_show(), 74 | bytes.len(), 75 | bytes 76 | ); 77 | 78 | // only for test circle to send-self. 79 | if bytes != vec![9, 9, 9, 9] { 80 | let _ = send 81 | .send(SendMessage::Data(9999, peer_id, vec![9, 9, 9, 9])) 82 | .await; 83 | } 84 | } 85 | ReceiveMessage::StableConnect(from, data) => { 86 | println!("Recv peer want to build a stable connected: {:?}", data); 87 | 88 | let tid = 2u64; 89 | 90 | let _ = send 91 | .send(SendMessage::StableResult( 92 | tid, 93 | from, 94 | true, 95 | false, 96 | vec![3, 3, 3, 3], 97 | )) 98 | .await; 99 | } 100 | ReceiveMessage::StableLeave(peer) => { 101 | println!("Recv stable connected leave: {:?}", peer); 102 | } 103 | ReceiveMessage::StableResult(peer, is_ok, remark) => { 104 | println!( 105 | "Recv stable connected result: {:?} {} {:?}", 106 | peer, is_ok, remark 107 | ); 108 | } 109 | ReceiveMessage::ResultConnect(from, _data) => { 110 | println!("Recv Result Connect {:?}", from); 111 | } 112 | ReceiveMessage::Delivery(t, tid, had, _data) => { 113 | println!("Recv {:?} Delivery: {} {}", t, tid, had); 114 | } 115 | ReceiveMessage::NetworkLost => { 116 | println!("No peers conneced.") 117 | } 118 | _ => { 119 | panic!("nerver here!"); 120 | } 121 | } 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /chamomile/examples/relay.rs: -------------------------------------------------------------------------------- 1 | use chamomile::prelude::{start, Config, Peer, ReceiveMessage, SendMessage}; 2 | use std::{env::args, net::SocketAddr}; 3 | use tracing::info; 4 | 5 | #[tokio::main] 6 | async fn main() { 7 | std::env::set_var("RUST_LOG", "info"); 8 | 9 | tracing_subscriber::fmt::init(); 10 | 11 | let addr_str = args().nth(1).unwrap_or("0.0.0.0:7364".to_owned()); 12 | let self_addr: SocketAddr = addr_str.parse().expect("invalid addr"); 13 | 14 | info!("START A INDEPENDENT P2P RELAY SERVER: {}", self_addr); 15 | 16 | let mut config = Config::default(Peer::socket(self_addr)); 17 | config.permission = false; 18 | config.only_stable_data = true; 19 | config.db_dir = std::path::PathBuf::from(".data/relay"); 20 | 21 | let (peer_id, send, mut recv) = start(config).await.unwrap(); 22 | info!("peer id: {}", peer_id.to_hex()); 23 | 24 | if args().nth(2).is_some() { 25 | let remote_addr: SocketAddr = args().nth(2).unwrap().parse().expect("invalid addr"); 26 | info!("start DHT connect to remote: {}", remote_addr); 27 | send.send(SendMessage::Connect(Peer::socket(remote_addr))) 28 | .await 29 | .expect("channel failure"); 30 | } 31 | 32 | while let Some(message) = recv.recv().await { 33 | match message { 34 | ReceiveMessage::StableConnect(from, ..) => { 35 | let _ = send 36 | .send(SendMessage::StableResult(0, from, false, false, vec![])) 37 | .await; 38 | } 39 | ReceiveMessage::ResultConnect(from, ..) => { 40 | let _ = send 41 | .send(SendMessage::StableResult(0, from, false, false, vec![])) 42 | .await; 43 | } 44 | _ => {} 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /chamomile/src/buffer.rs: -------------------------------------------------------------------------------- 1 | use std::collections::HashMap; 2 | use std::net::SocketAddr; 3 | use tokio::sync::mpsc::Sender; 4 | 5 | use chamomile_types::{Peer, PeerId}; 6 | 7 | use crate::kad::KadValue; 8 | use crate::session::SessionMessage; 9 | use crate::transports::EndpointMessage; 10 | 11 | #[derive(Hash, Eq, PartialEq, Clone)] 12 | pub enum BufferKey { 13 | Peer(PeerId), 14 | Addr(SocketAddr), 15 | } 16 | 17 | pub(crate) struct Buffer { 18 | /// queue for connect to ip addr. if has one, not send aggin. 19 | dhts: HashMap, 20 | /// queue for stable connect to peer id. if has one, add to queue buffer. 21 | connects: HashMap)>)>, 22 | /// queue for stable result to peer id. if has one, add to queue buffer. 23 | results: HashMap)>)>, 24 | /// tmp stable waiting outside to stable result. 60s if no-ok, close it. 25 | tmps: HashMap, 26 | } 27 | 28 | impl Buffer { 29 | pub fn init() -> Self { 30 | Buffer { 31 | dhts: HashMap::new(), 32 | connects: HashMap::new(), 33 | results: HashMap::new(), 34 | tmps: HashMap::new(), 35 | } 36 | } 37 | 38 | pub fn _add_dht(&mut self, ip: &SocketAddr) -> bool { 39 | if self.dhts.contains_key(ip) { 40 | false 41 | } else { 42 | self.dhts.insert(*ip, false); 43 | true 44 | } 45 | } 46 | 47 | pub fn _remove_dht(&mut self, ip: &SocketAddr) { 48 | self.dhts.remove(ip); 49 | } 50 | 51 | /// Result is already had or none. 52 | pub fn add_connect(&mut self, key: BufferKey, tid: u64, data: Vec) -> bool { 53 | if let Some(v) = self.connects.get_mut(&key) { 54 | v.1.push((tid, data)); 55 | true 56 | } else { 57 | self.connects.insert(key, (false, vec![(tid, data)])); 58 | false 59 | } 60 | } 61 | 62 | pub fn remove_connect(&mut self, key: BufferKey) -> Vec<(u64, Vec)> { 63 | self.connects.remove(&key).map(|v| v.1).unwrap_or(vec![]) 64 | } 65 | 66 | pub fn add_result(&mut self, peer_id: PeerId, tid: u64, data: Vec) -> bool { 67 | if let Some(v) = self.results.get_mut(&peer_id) { 68 | v.1.push((tid, data)); 69 | true 70 | } else { 71 | self.results.insert(peer_id, (false, vec![(tid, data)])); 72 | false 73 | } 74 | } 75 | 76 | pub fn remove_result(&mut self, peer_id: &PeerId) -> Vec<(u64, Vec)> { 77 | self.results.remove(peer_id).map(|v| v.1).unwrap_or(vec![]) 78 | } 79 | 80 | pub fn remove_stable(&mut self, peer_id: &PeerId) { 81 | self.connects.remove(&BufferKey::Peer(*peer_id)); 82 | self.results.remove(peer_id); 83 | } 84 | 85 | pub fn get_tmp_session(&self, peer_id: &PeerId) -> Option<&Sender> { 86 | self.tmps.get(peer_id).map(|(_, v, _)| &v.0) 87 | } 88 | 89 | pub fn get_tmp_stream(&self, peer_id: &PeerId) -> Option<&Sender> { 90 | self.tmps.get(peer_id).map(|(_, v, _)| &v.1) 91 | } 92 | 93 | pub fn add_tmp(&mut self, peer_id: PeerId, value: KadValue, is_d: bool) { 94 | self.tmps.insert(peer_id, (false, value, is_d)); 95 | } 96 | 97 | pub fn update_peer(&mut self, peer_id: &PeerId, peer: Peer) { 98 | self.tmps.get_mut(peer_id).map(|(_, v, _)| v.2 = peer); 99 | } 100 | 101 | pub fn remove_tmp(&mut self, peer_id: &PeerId) -> Option<(KadValue, bool)> { 102 | self.tmps.remove(peer_id).map(|(_, v, is_d)| (v, is_d)) 103 | } 104 | 105 | pub async fn timer_clear(&mut self) { 106 | let mut dht_deletes = vec![]; 107 | for (ip, t) in self.dhts.iter_mut() { 108 | if *t { 109 | dht_deletes.push(*ip); 110 | } else { 111 | *t = true; // checked. 112 | } 113 | } 114 | for ip in dht_deletes { 115 | self.dhts.remove(&ip); 116 | } 117 | 118 | let mut connect_deletes = vec![]; 119 | for (id, (t, _)) in self.connects.iter_mut() { 120 | if *t { 121 | connect_deletes.push(id.clone()); 122 | } else { 123 | *t = true; // checked. 124 | } 125 | } 126 | for id in connect_deletes { 127 | self.connects.remove(&id); 128 | } 129 | 130 | let mut result_deletes = vec![]; 131 | for (id, (t, _)) in self.results.iter_mut() { 132 | if *t { 133 | result_deletes.push(*id); 134 | } else { 135 | *t = true; // checked. 136 | } 137 | } 138 | for id in result_deletes { 139 | self.results.remove(&id); 140 | } 141 | 142 | let mut tmp_deletes = vec![]; 143 | for (id, (t, KadValue(ss, _, _), _)) in self.tmps.iter_mut() { 144 | if *t { 145 | let _ = ss.send(SessionMessage::Close).await; 146 | tmp_deletes.push(*id); 147 | } else { 148 | *t = true; // checked. 149 | } 150 | } 151 | for id in tmp_deletes { 152 | self.tmps.remove(&id); 153 | } 154 | } 155 | } 156 | -------------------------------------------------------------------------------- /chamomile/src/config.rs: -------------------------------------------------------------------------------- 1 | use std::net::IpAddr; 2 | use std::path::PathBuf; 3 | 4 | use chamomile_types::{Peer, PeerId}; 5 | 6 | /// Chammomile Configs. 7 | #[derive(Debug, Clone)] 8 | pub struct Config { 9 | /// Default Data saved directory. 10 | pub db_dir: PathBuf, 11 | /// Default binding multiaddr string. 12 | /// Example: "/ip4/0.0.0.0/quic/7364" 13 | pub peer: Peer, 14 | /// Allowed MultiAddr style peer list. 15 | pub allowlist: Vec, 16 | /// Blocked Ip's list. 17 | pub blocklist: Vec, 18 | /// Allowed peer's `PeerId` list. 19 | pub allow_peer_list: Vec, 20 | /// Blocked peers's `PeerId` list. 21 | pub block_peer_list: Vec, 22 | /// If set permission is true, that server is permissioned, 23 | /// not receive DHT's peer message, only stable connect. 24 | /// if set permission is false, that server is permissionless, 25 | /// receive DHT's peer message and stable's peer message. 26 | /// if you use a permissionless server, but only receive stable's message, 27 | /// you can set `only_stable_data` is true. 28 | /// Recommend use `permission = false & only_stable_data = true` replace permissioned. 29 | pub permission: bool, 30 | /// If `only_stable_data` is true, only receive stable connected peer's data. 31 | pub only_stable_data: bool, 32 | /// When delivery feedback has set length, it will split length of data to return. 33 | /// For example. set `delivery_length = 8`, 34 | /// and when a `Data(1u64, PeerId, vec![1u8, 2u8, ..., 100u8]), 35 | /// if send success, will return: 36 | /// `Delivery(DeliveryType::Data, 1u64, true, vec![1u8, 2u8, ..., 8u8])` 37 | /// if send failure, will return: 38 | /// `Delivery(DeliveryType::Data, 1u64, false, vec![1u8, 2u8, ..., 8u8])` 39 | pub delivery_length: usize, 40 | } 41 | 42 | impl Config { 43 | pub fn default(peer: Peer) -> Self { 44 | Self { 45 | db_dir: PathBuf::from("./"), 46 | peer: peer, 47 | allowlist: vec![], 48 | blocklist: vec![], 49 | allow_peer_list: vec![], 50 | block_peer_list: vec![], 51 | permission: false, 52 | only_stable_data: false, 53 | delivery_length: 0, 54 | } 55 | } 56 | 57 | pub fn new( 58 | db_dir: PathBuf, 59 | peer: Peer, 60 | allowlist: Vec, 61 | blocklist: Vec, 62 | allow_peer_list: Vec, 63 | block_peer_list: Vec, 64 | permission: bool, 65 | only_stable_data: bool, 66 | delivery_length: usize, 67 | ) -> Self { 68 | Self { 69 | db_dir, 70 | peer, 71 | allowlist, 72 | blocklist, 73 | allow_peer_list, 74 | block_peer_list, 75 | permission, 76 | only_stable_data, 77 | delivery_length, 78 | } 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /chamomile/src/global.rs: -------------------------------------------------------------------------------- 1 | use std::collections::HashMap; 2 | use std::sync::Arc; 3 | use tokio::{ 4 | io::Result, 5 | sync::{mpsc::Sender, RwLock}, 6 | }; 7 | 8 | use chamomile_types::{ 9 | key::Key, 10 | message::ReceiveMessage, 11 | types::{new_io_error, TransportType}, 12 | Peer, PeerId, 13 | }; 14 | 15 | use crate::buffer::{Buffer, BufferKey}; 16 | use crate::kad::KadValue; 17 | use crate::peer_list::PeerList; 18 | use crate::session_key::SessionKey; 19 | use crate::transports::{start, RemotePublic, TransportRecvMessage, TransportSendMessage}; 20 | 21 | pub(crate) struct Global { 22 | pub peer: Peer, 23 | pub key: Key, 24 | pub trans: Sender, 25 | pub transports: Arc>>>, 26 | pub out_sender: Sender, 27 | pub peer_list: Arc>, 28 | pub buffer: Arc>, 29 | pub is_relay_data: bool, 30 | pub delivery_length: usize, 31 | } 32 | 33 | impl Global { 34 | #[inline] 35 | pub fn peer_id(&self) -> &PeerId { 36 | &self.peer.id 37 | } 38 | 39 | #[inline] 40 | pub fn assist_id(&self) -> &PeerId { 41 | &self.peer.assist 42 | } 43 | 44 | #[inline] 45 | pub fn generate_remote(&self) -> (SessionKey, RemotePublic) { 46 | let (session_key, dh_bytes) = SessionKey::generate(&self.key); 47 | let remote_pk = RemotePublic(self.peer.clone(), dh_bytes); 48 | (session_key, remote_pk) 49 | } 50 | 51 | #[inline] 52 | pub fn complete_remote( 53 | &self, 54 | remote_id: &PeerId, 55 | dh_bytes: Vec, 56 | ) -> Option<(SessionKey, RemotePublic)> { 57 | if let Some((session_key, dh_bytes)) = 58 | SessionKey::generate_complete(&self.key, remote_id, dh_bytes) 59 | { 60 | let remote_pk = RemotePublic(self.peer.clone(), dh_bytes); 61 | Some((session_key, remote_pk)) 62 | } else { 63 | None 64 | } 65 | } 66 | 67 | #[inline] 68 | pub async fn trans_send( 69 | &self, 70 | trans_type: &TransportType, 71 | msg: TransportSendMessage, 72 | ) -> Result<()> { 73 | let trans_lock = self.transports.read().await; 74 | if let Some(sender) = trans_lock.get(trans_type) { 75 | sender 76 | .send(msg) 77 | .await 78 | .map_err(|_e| new_io_error("Transport missing")) 79 | } else { 80 | drop(trans_lock); 81 | // start new transport to send it. 82 | // Only TCP & QUIC 83 | let main_send = self.trans.clone(); 84 | let mut new_peer = self.peer.clone(); 85 | new_peer.transport = *trans_type; 86 | new_peer.zero_port(); 87 | 88 | let (_, trans_send, _, _) = start(&new_peer, Some(main_send)).await?; 89 | trans_send 90 | .send(msg) 91 | .await 92 | .map_err(|_e| new_io_error("Transport missing"))?; 93 | self.transports 94 | .write() 95 | .await 96 | .insert(*trans_type, trans_send); 97 | Ok(()) 98 | } 99 | } 100 | 101 | #[inline] 102 | pub async fn out_send(&self, msg: ReceiveMessage) -> Result<()> { 103 | self.out_sender 104 | .send(msg) 105 | .await 106 | .map_err(|_e| new_io_error("Outside missing")) 107 | } 108 | 109 | pub async fn add_tmp( 110 | &self, 111 | p: PeerId, 112 | buffer: BufferKey, 113 | k: KadValue, 114 | d: bool, 115 | ) -> Vec<(u64, Vec)> { 116 | let mut buffer_lock = self.buffer.write().await; 117 | let stables = buffer_lock.remove_connect(buffer); 118 | buffer_lock.add_tmp(p, k, d); 119 | drop(buffer_lock); 120 | stables 121 | } 122 | 123 | pub async fn add_all_tmp( 124 | &self, 125 | peer_id: PeerId, 126 | kv: KadValue, 127 | is_direct: bool, 128 | ) -> (Vec<(u64, Vec)>, Vec<(u64, Vec)>) { 129 | let mut buffer_lock = self.buffer.write().await; 130 | let connects = buffer_lock.remove_connect(BufferKey::Peer(peer_id)); 131 | let results = buffer_lock.remove_result(&peer_id); 132 | buffer_lock.add_tmp(peer_id, kv, is_direct); 133 | drop(buffer_lock); 134 | 135 | (connects, results) 136 | } 137 | 138 | pub async fn upgrade(&self, peer_id: &PeerId, assist_id: &PeerId) -> Result<()> { 139 | let v_some = self.buffer.write().await.remove_tmp(peer_id); 140 | if let Some((v, is_d)) = v_some { 141 | self.peer_list.write().await.add_stable(*peer_id, v, is_d); 142 | Ok(()) 143 | } else { 144 | self.peer_list 145 | .write() 146 | .await 147 | .dht_to_stable(peer_id, assist_id) 148 | } 149 | } 150 | 151 | pub async fn upgrade_own(&self, peer_id: &PeerId) { 152 | let v_some = self.buffer.write().await.remove_tmp(peer_id); 153 | if let Some((v, is_d)) = v_some { 154 | self.peer_list.write().await.add_own(*peer_id, v, is_d); 155 | } 156 | } 157 | 158 | pub async fn tmp_to_dht(&self, peer_id: &PeerId) -> Result<()> { 159 | let v_some = self.buffer.write().await.remove_tmp(peer_id); 160 | if let Some((v, is_d)) = v_some { 161 | if is_d { 162 | if self.peer_list.write().await.add_dht(v).await { 163 | return Ok(()); 164 | } 165 | } 166 | } 167 | Err(new_io_error("missing buffer")) 168 | } 169 | 170 | #[inline] 171 | pub async fn stable_to_dht(&self, peer_id: &PeerId) -> Result<()> { 172 | let mut buffer_lock = self.buffer.write().await; 173 | buffer_lock.remove_tmp(peer_id); 174 | buffer_lock.remove_stable(peer_id); 175 | drop(buffer_lock); 176 | 177 | self.peer_list.write().await.stable_to_dht(peer_id) 178 | } 179 | } 180 | -------------------------------------------------------------------------------- /chamomile/src/hole_punching.rs: -------------------------------------------------------------------------------- 1 | use std::io::Result; 2 | use std::net::SocketAddr; 3 | 4 | use chamomile_types::{ 5 | peer::{Peer, PEER_LENGTH}, 6 | types::{new_io_error, PeerId, TransportType}, 7 | }; 8 | 9 | use super::peer_list::PeerList; 10 | 11 | pub enum Hole { 12 | StunOne, 13 | StunTwo, 14 | Help, 15 | } 16 | 17 | pub struct DHT(pub Vec); 18 | 19 | impl Hole { 20 | pub fn from_byte(byte: u8) -> Result { 21 | match byte { 22 | 0u8 => Ok(Hole::Help), 23 | 1u8 => Ok(Hole::StunOne), 24 | 2u8 => Ok(Hole::StunTwo), 25 | _ => Err(new_io_error("Hole bytes failure.")), 26 | } 27 | } 28 | 29 | pub fn to_byte(&self) -> u8 { 30 | match self { 31 | Hole::Help => 0u8, 32 | Hole::StunOne => 1u8, 33 | Hole::StunTwo => 2u8, 34 | } 35 | } 36 | } 37 | 38 | impl DHT { 39 | pub fn from_bytes(bytes: &[u8]) -> Result { 40 | if bytes.len() < 4 { 41 | return Err(new_io_error("DHT bytes failure.")); 42 | } 43 | let mut len_bytes = [0u8; 4]; 44 | len_bytes.copy_from_slice(&bytes[0..4]); 45 | let len = u32::from_le_bytes(len_bytes) as usize; 46 | let raw_bytes = &bytes[4..]; 47 | if raw_bytes.len() < len * PEER_LENGTH { 48 | return Err(new_io_error("DHT bytes failure.")); 49 | } 50 | let mut peers = vec![]; 51 | for i in 0..len { 52 | peers.push(Peer::from_bytes( 53 | &raw_bytes[i * PEER_LENGTH..(i + 1) * PEER_LENGTH], 54 | )?); 55 | } 56 | Ok(Self(peers)) 57 | } 58 | 59 | pub fn to_bytes(&self) -> Vec { 60 | let mut bytes = vec![]; 61 | bytes.extend(&(self.0.len() as u32).to_le_bytes()); 62 | for peer in &self.0 { 63 | bytes.append(&mut peer.to_bytes()); 64 | } 65 | bytes 66 | } 67 | } 68 | 69 | pub fn nat(mut remote_addr: SocketAddr, mut local: Peer) -> Peer { 70 | local.is_pub = remote_addr.port() == local.socket.port(); 71 | match local.transport { 72 | TransportType::TCP => { 73 | remote_addr.set_port(local.socket.port()); // TODO TCP hole punching 74 | } 75 | _ => {} 76 | } 77 | 78 | local.socket = remote_addr; 79 | local 80 | } 81 | 82 | pub(crate) async fn _handle(_remote_peer: &PeerId, hole: Hole, _peers: &PeerList) -> Result<()> { 83 | match hole { 84 | Hole::StunOne => { 85 | // first test 86 | } 87 | Hole::StunTwo => { 88 | // secound test 89 | } 90 | Hole::Help => { 91 | // help hole 92 | } 93 | } 94 | 95 | Ok(()) 96 | } 97 | -------------------------------------------------------------------------------- /chamomile/src/kad.rs: -------------------------------------------------------------------------------- 1 | use bit_vec::BitVec; 2 | use core::cmp::Ordering; 3 | use rand_chacha::{ 4 | rand_core::{RngCore, SeedableRng}, 5 | ChaChaRng, 6 | }; 7 | use std::collections::HashMap; 8 | use std::net::SocketAddr; 9 | use tokio::sync::mpsc::Sender; 10 | 11 | use chamomile_types::{Peer, PeerId}; 12 | 13 | use crate::session::SessionMessage; 14 | use crate::transports::EndpointMessage; 15 | 16 | trait Key: Eq + Clone { 17 | const KEY_LENGTH: usize; 18 | fn distance(&self) -> Distance; 19 | fn calc_distance(base: &Self, target: &Self) -> Distance { 20 | let base = base.distance(); 21 | let target = target.distance(); 22 | base.xor(&target, Self::KEY_LENGTH) 23 | } 24 | } 25 | 26 | impl Key for PeerId { 27 | const KEY_LENGTH: usize = 160; 28 | fn distance(&self) -> Distance { 29 | // 160-bit 30 | Distance(BitVec::from_bytes(self.as_bytes())) 31 | } 32 | } 33 | 34 | impl Key for SocketAddr { 35 | const KEY_LENGTH: usize = 144; 36 | fn distance(&self) -> Distance { 37 | let ip_bytes: [u8; 16] = match self { 38 | SocketAddr::V4(ipv4) => ipv4.ip().to_ipv6_mapped().octets(), 39 | SocketAddr::V6(ipv6) => ipv6.ip().octets(), 40 | }; 41 | let port_bytes: [u8; 2] = self.port().to_le_bytes(); 42 | // 144-bit = 128 + 16 43 | Distance(BitVec::from_bytes( 44 | &[&ip_bytes[..], &port_bytes[..]].concat(), 45 | )) 46 | } 47 | } 48 | 49 | const MAX_LEVEL: usize = 8; 50 | 51 | // max peer-id is 4 * 160 = 640 52 | // max ip-address is 4 * 128 = 512 53 | // max assists is 4 * 160 = 640 54 | const K_BUCKET: usize = 4; 55 | 56 | pub(crate) struct KadValue( 57 | pub Sender, 58 | pub Sender, 59 | pub Peer, 60 | ); 61 | 62 | pub(crate) struct DoubleKadTree { 63 | /// index => (in_peers, [value]) 64 | pub values: HashMap)>, 65 | peers: KadTree, 66 | assists: KadTree, 67 | ips: KadTree, 68 | } 69 | 70 | struct KadTree { 71 | root_key: K, 72 | left: TreeNode, 73 | right: TreeNode, 74 | } 75 | 76 | type TreeNode = Option>>; 77 | 78 | struct Node { 79 | left: TreeNode, 80 | right: TreeNode, 81 | list: Vec>, 82 | } 83 | 84 | struct Cell(K, u32, Distance); 85 | 86 | impl DoubleKadTree { 87 | pub fn new(root_peer: PeerId, root_assist: PeerId, root_ip: SocketAddr) -> Self { 88 | DoubleKadTree { 89 | peers: KadTree::new(root_peer), 90 | assists: KadTree::new(root_assist), 91 | ips: KadTree::new(root_ip), 92 | values: HashMap::new(), 93 | } 94 | } 95 | 96 | fn gen_index() -> u32 { 97 | let mut rng = ChaChaRng::from_entropy(); 98 | loop { 99 | let v = rng.next_u32(); 100 | if v > 0 { 101 | return v; 102 | } 103 | } 104 | } 105 | 106 | pub fn add(&mut self, value: KadValue) -> bool { 107 | let value_key = Self::gen_index(); 108 | let peer_id = value.2.id; 109 | let assist_id = value.2.assist; 110 | let ip_addr = value.2.socket; 111 | let (is_ok_p, key_p, removed_p) = self.peers.add(peer_id, value_key); 112 | let (is_ok_a, key_a, removed_a) = self.assists.add(assist_id, key_p); 113 | if removed_p > 0 { 114 | let mut deletable = false; 115 | if let Some((p, v)) = self.values.get_mut(&removed_p) { 116 | if removed_p == removed_a && v.len() < 2 { 117 | deletable = true; 118 | } else { 119 | *p = false; 120 | } 121 | } 122 | 123 | if deletable { 124 | if let Some((_, v)) = self.values.remove(&removed_p) { 125 | for va in v { 126 | self.ips.remove(&va.2.socket); 127 | } 128 | } 129 | } 130 | } 131 | 132 | if removed_a > 0 { 133 | let mut deletable = false; 134 | if let Some((p, v)) = self.values.get_mut(&removed_a) { 135 | if !*p && v.len() < 2 { 136 | deletable = true; 137 | } else { 138 | let mut index = 0; 139 | for (i, va) in v.iter().enumerate() { 140 | if va.2.assist == assist_id { 141 | self.ips.remove(&va.2.socket); 142 | index = i; 143 | } 144 | } 145 | 146 | v.remove(index); 147 | } 148 | } 149 | 150 | if deletable { 151 | if let Some((_, v)) = self.values.remove(&removed_p) { 152 | for va in v { 153 | self.ips.remove(&va.2.socket); 154 | } 155 | } 156 | } 157 | } 158 | 159 | if is_ok_p || is_ok_a { 160 | if key_a != value_key && self.values.contains_key(&key_a) { 161 | if let Some((is_p, v)) = self.values.get_mut(&key_a) { 162 | *is_p = is_ok_p; 163 | if is_ok_a { 164 | for va in v.iter() { 165 | if va.2.assist == assist_id { 166 | return true; 167 | } 168 | } 169 | v.push(value); 170 | } 171 | } 172 | } else { 173 | self.ips.add(ip_addr, key_a); 174 | self.values.insert(key_a, (is_ok_p, vec![value])); 175 | } 176 | 177 | true 178 | } else { 179 | false 180 | } 181 | } 182 | 183 | pub fn id_next_closest(&self, key: &PeerId, prev: &[PeerId]) -> Option<&KadValue> { 184 | let p_v = self 185 | .peers 186 | .next_closest(key, prev) 187 | .map(|(k, _p)| self.values.get(k)) 188 | .flatten() 189 | .map(|v| &(v.1)[0]); 190 | let a_v = self 191 | .assists 192 | .next_closest(key, prev) 193 | .map(|(k, p)| self.values.get(k).map(|v| (v, p))) 194 | .flatten() 195 | .map(|(v, p)| { 196 | for va in &v.1 { 197 | if &va.2.assist == p { 198 | return va; 199 | } 200 | } 201 | &(v.1)[0] 202 | }); 203 | match (p_v, a_v) { 204 | (Some(_p), Some(a)) => { 205 | if &a.2.assist == key { 206 | a_v 207 | } else { 208 | p_v 209 | } 210 | } 211 | _ => p_v.or(a_v), 212 | } 213 | } 214 | 215 | pub fn _ip_next_closest(&self, key: &SocketAddr, prev: &[SocketAddr]) -> Option<&KadValue> { 216 | self.ips 217 | .next_closest(key, prev) 218 | .map(|(k, _)| self.values.get(k)) 219 | .flatten() 220 | .map(|v| &(v.1)[0]) 221 | } 222 | 223 | pub fn search(&self, key: &PeerId) -> Option<(&KadValue, bool)> { 224 | if let Some((v, is_it)) = self 225 | .assists 226 | .search(key) 227 | .map(|(_, k, is_it)| self.values.get(k).map(|(_, v)| (&v[0], is_it))) 228 | .flatten() 229 | { 230 | if is_it { 231 | return Some((v, true)); 232 | } 233 | } 234 | 235 | self.peers 236 | .search(key) 237 | .map(|(_, k, is_it)| self.values.get(k).map(|(_, v)| (&v[0], is_it))) 238 | .flatten() 239 | } 240 | 241 | pub fn take(&mut self, key: &PeerId, assist: &PeerId) -> Option> { 242 | match (self.peers.remove(key), self.assists.remove(assist)) { 243 | (Some(k), _) | (_, Some(k)) => { 244 | if let Some((_, value)) = self.values.remove(&k) { 245 | self.ips.remove(&(value[0]).2.socket); 246 | let mut vs = vec![]; 247 | for v in value { 248 | self.assists.remove(&v.2.assist); 249 | vs.push(v); 250 | } 251 | Some(vs) 252 | } else { 253 | None 254 | } 255 | } 256 | _ => None, 257 | } 258 | } 259 | 260 | pub fn remove(&mut self, key: &PeerId, assist: &PeerId) { 261 | if let Some(k) = self.assists.remove(assist) { 262 | if let Some((_, v)) = self.values.get_mut(&k) { 263 | let mut index = 0; 264 | for (i, v) in v.iter().enumerate() { 265 | if &v.2.assist == assist { 266 | index = i; 267 | } 268 | } 269 | v.remove(index); 270 | if v.len() > 0 { 271 | return; 272 | } 273 | } 274 | } 275 | if let Some(k) = self.peers.remove(key) { 276 | if let Some((_, v)) = self.values.remove(&k) { 277 | for va in v { 278 | self.ips.remove(&va.2.socket); 279 | } 280 | } 281 | } 282 | } 283 | 284 | pub fn contains(&self, key: &PeerId) -> bool { 285 | self.peers.contains(key) 286 | } 287 | 288 | pub fn keys(&self) -> Vec { 289 | self.peers.keys() 290 | } 291 | 292 | pub fn is_empty(&self) -> bool { 293 | self.peers.is_empty() 294 | } 295 | } 296 | 297 | impl KadTree { 298 | fn new(key: K) -> Self { 299 | KadTree { 300 | root_key: key, 301 | left: None, 302 | right: None, 303 | } 304 | } 305 | 306 | fn add(&mut self, key: K, value: u32) -> (bool, u32, u32) { 307 | let distance = K::calc_distance(&self.root_key, &key); 308 | 309 | if distance.get(0) { 310 | if self.right.is_none() { 311 | self.right = Some(Box::new(Node::default())); 312 | } 313 | self.right 314 | .as_mut() 315 | .and_then(|v| Some(v.insert(Cell(key, value, distance), 1, K_BUCKET))) 316 | .unwrap() // safe checked. 317 | } else { 318 | if self.left.is_none() { 319 | self.left = Some(Box::new(Node::default())); 320 | } 321 | self.left 322 | .as_mut() 323 | .and_then(|v| Some(v.insert(Cell(key, value, distance), 1, K_BUCKET))) 324 | .unwrap() // safe checked. 325 | } 326 | } 327 | 328 | fn next_closest(&self, key: &K, prev: &[K]) -> Option<(&u32, &K)> { 329 | self.search(key) 330 | .map(|v| { 331 | if prev.contains(v.0) { 332 | None 333 | } else { 334 | Some((v.1, v.0)) 335 | } 336 | }) 337 | .flatten() 338 | } 339 | 340 | fn search(&self, key: &K) -> Option<(&K, &u32, bool)> { 341 | let distance = K::calc_distance(&self.root_key, &key); 342 | 343 | if distance.get(0) { 344 | if self.right.is_none() { 345 | if self.left.is_none() { 346 | None 347 | } else { 348 | self.left 349 | .as_ref() 350 | .and_then(|v| Some(v.search(key, &distance, 1))) 351 | .unwrap() // safe checked. 352 | } 353 | } else { 354 | self.right 355 | .as_ref() 356 | .and_then(|v| Some(v.search(key, &distance, 1))) 357 | .unwrap() // safe chekced. 358 | } 359 | } else { 360 | if self.left.is_none() { 361 | if self.right.is_none() { 362 | None 363 | } else { 364 | self.right 365 | .as_ref() 366 | .and_then(|v| Some(v.search(key, &distance, 1))) 367 | .unwrap() // safe checked. 368 | } 369 | } else { 370 | self.left 371 | .as_ref() 372 | .and_then(|v| Some(v.search(key, &distance, 1))) 373 | .unwrap() // safe checked. 374 | } 375 | } 376 | } 377 | 378 | fn remove(&mut self, key: &K) -> Option { 379 | let distance = K::calc_distance(&self.root_key, &key); 380 | if distance.get(0) { 381 | self.right 382 | .as_mut() 383 | .and_then(|v| v.remove(key, &distance, 1)) 384 | } else { 385 | self.left.as_mut().and_then(|v| v.remove(key, &distance, 1)) 386 | } 387 | } 388 | 389 | fn contains(&self, key: &K) -> bool { 390 | if let Some((_, _, true)) = self.search(key) { 391 | true 392 | } else { 393 | false 394 | } 395 | } 396 | 397 | fn keys(&self) -> Vec { 398 | let mut vec = Vec::new(); 399 | if self.left.is_some() { 400 | self.left.as_ref().unwrap().keys(&mut vec); // safe checked. 401 | } 402 | if self.right.is_some() { 403 | self.right.as_ref().unwrap().keys(&mut vec); // safe checked. 404 | } 405 | vec 406 | } 407 | 408 | fn is_empty(&self) -> bool { 409 | if self.left.is_some() { 410 | if !self.left.as_ref().unwrap().is_empty() { 411 | return false; 412 | } 413 | } 414 | if self.right.is_some() { 415 | if !self.right.as_ref().unwrap().is_empty() { 416 | return false; 417 | } 418 | } 419 | 420 | true 421 | } 422 | } 423 | 424 | impl Node { 425 | fn default() -> Self { 426 | Node { 427 | left: None, 428 | right: None, 429 | list: Vec::new(), 430 | } 431 | } 432 | 433 | fn insert(&mut self, mut cell: Cell, index: usize, k_bucket: usize) -> (bool, u32, u32) { 434 | if self.right.is_some() || self.left.is_some() { 435 | if cell.2.get(index) { 436 | if self.right.is_none() { 437 | self.right = Some(Box::new(Node::default())); 438 | } 439 | self.right 440 | .as_mut() 441 | .and_then(|v| Some(v.insert(cell, index + 1, k_bucket))) 442 | .unwrap() // safe checked. 443 | } else { 444 | if self.left.is_none() { 445 | self.left = Some(Box::new(Node::default())); 446 | } 447 | self.left 448 | .as_mut() 449 | .and_then(|v| Some(v.insert(cell, index + 1, k_bucket))) 450 | .unwrap() // safe checked. 451 | } 452 | } else { 453 | // check if in the lists. 454 | for c in &self.list { 455 | if c == &cell { 456 | return (true, c.1, 0); 457 | } 458 | } 459 | let v_index = cell.1; 460 | 461 | if self.list.len() < k_bucket { 462 | self.list.push(cell); 463 | (true, v_index, 0) 464 | } else { 465 | if index >= MAX_LEVEL { 466 | for v in self.list.iter_mut() { 467 | if v > &mut cell { 468 | let removed = v.1; 469 | *v = cell; 470 | return (true, v_index, removed); 471 | } 472 | } 473 | return (false, v_index, 0); 474 | } else { 475 | self.right = Some(Box::new(Node::default())); 476 | self.left = Some(Box::new(Node::default())); 477 | 478 | while !self.list.is_empty() { 479 | let new_cell = self.list.remove(0); 480 | self.insert(new_cell, index, k_bucket); 481 | } 482 | 483 | self.insert(cell, index, k_bucket) 484 | } 485 | } 486 | } 487 | } 488 | 489 | pub fn search(&self, key: &K, distance: &Distance, index: usize) -> Option<(&K, &u32, bool)> { 490 | let mut closest_index = usize::MAX; 491 | let mut closest_distance = Distance::max(K::KEY_LENGTH); 492 | 493 | for (index, cell) in self.list.iter().enumerate() { 494 | if &cell.0 == key { 495 | return Some((&cell.0, &cell.1, true)); 496 | } else { 497 | let dis = distance.xor(&cell.2, K::KEY_LENGTH); 498 | if dis < closest_distance { 499 | closest_distance = dis; 500 | closest_index = index; 501 | } 502 | } 503 | } 504 | 505 | if distance.get(index) { 506 | if let Some(ref right) = self.right { 507 | let next = right.search(key, distance, index + 1); 508 | if next.is_some() { 509 | return next; 510 | } 511 | } 512 | } else { 513 | if let Some(ref left) = self.left { 514 | let next = left.search(key, distance, index + 1); 515 | if next.is_some() { 516 | return next; 517 | } 518 | } 519 | } 520 | 521 | self.list 522 | .get(closest_index) 523 | .and_then(|cell| Some((&cell.0, &cell.1, false))) 524 | } 525 | 526 | pub fn remove(&mut self, key: &K, distance: &Distance, index: usize) -> Option { 527 | let mut deleted_index = usize::MAX; 528 | for (i, cell) in self.list.iter().enumerate() { 529 | if &cell.0 == key { 530 | deleted_index = i; 531 | } 532 | } 533 | 534 | if deleted_index != usize::MAX { 535 | let Cell(_k, v, _d) = self.list.remove(deleted_index); 536 | return Some(v); 537 | } 538 | 539 | if distance.get(index) { 540 | if let Some(ref mut right) = self.right { 541 | return right.remove(key, distance, index + 1); 542 | } 543 | } else { 544 | if let Some(ref mut left) = self.left { 545 | return left.remove(key, distance, index + 1); 546 | } 547 | } 548 | 549 | None 550 | } 551 | 552 | pub fn keys(&self, vec: &mut Vec) { 553 | for i in self.list.iter() { 554 | vec.push(i.key().clone()); 555 | } 556 | 557 | if let Some(ref left) = self.left { 558 | left.keys(vec); 559 | } 560 | 561 | if let Some(ref right) = self.right { 562 | right.keys(vec); 563 | } 564 | } 565 | 566 | pub fn is_empty(&self) -> bool { 567 | if !self.list.is_empty() { 568 | return false; 569 | } 570 | 571 | if let Some(ref left) = self.left { 572 | if !left.is_empty() { 573 | return false; 574 | } 575 | } 576 | 577 | if let Some(ref right) = self.right { 578 | if !right.is_empty() { 579 | return false; 580 | } 581 | } 582 | 583 | true 584 | } 585 | } 586 | 587 | impl Ord for Cell { 588 | fn cmp(&self, other: &Self) -> Ordering { 589 | self.2.cmp(&other.2) 590 | } 591 | } 592 | 593 | impl PartialOrd for Cell { 594 | fn partial_cmp(&self, other: &Self) -> Option { 595 | Some(self.cmp(other)) 596 | } 597 | } 598 | 599 | impl Eq for Cell {} 600 | 601 | impl PartialEq for Cell { 602 | fn eq(&self, other: &Self) -> bool { 603 | self.0 == other.0 604 | } 605 | } 606 | 607 | impl Cell { 608 | fn key(&self) -> &K { 609 | &self.0 610 | } 611 | } 612 | 613 | #[derive(Eq, PartialEq, Ord, PartialOrd, Debug)] 614 | pub struct Distance(BitVec); 615 | 616 | impl Distance { 617 | fn max(len: usize) -> Self { 618 | Distance(BitVec::from_elem(len, true)) 619 | } 620 | 621 | fn min(len: usize) -> Self { 622 | Distance(BitVec::from_elem(len, false)) 623 | } 624 | 625 | fn get(&self, index: usize) -> bool { 626 | if index >= 160 { 627 | false 628 | } else { 629 | self.0[index] 630 | } 631 | } 632 | 633 | fn xor(&self, other: &Distance, len: usize) -> Distance { 634 | let mut new_binary = BitVec::from_elem(len, false); 635 | 636 | for i in 0..len { 637 | if self.0[i] != other.0[i] { 638 | new_binary.set(i, true); 639 | } else { 640 | new_binary.set(i, false); 641 | } 642 | } 643 | 644 | Distance(new_binary) 645 | } 646 | } 647 | 648 | impl Default for Distance { 649 | fn default() -> Self { 650 | Distance::min(160) 651 | } 652 | } 653 | -------------------------------------------------------------------------------- /chamomile/src/lan.rs: -------------------------------------------------------------------------------- 1 | //! Multicasting(IPv4) & Broadcasting(IPv6) 2 | //! Searching Peer In LAN. and UPnP with SSDP. 3 | 4 | // WIP 5 | -------------------------------------------------------------------------------- /chamomile/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![recursion_limit = "1024"] 2 | 3 | //! `chamomile` is a crate for building a solid and efficient p2p network. 4 | //! 5 | //! # Example Use 6 | //! 7 | //! We running a p2p peer, and if others add, we will get the info. 8 | //! 9 | //! ```ignore 10 | //! use std::env::args; 11 | //! use std::net::SocketAddr; 12 | //! use std::path::PathBuf; 13 | //! 14 | //! use chamomile::prelude::{start, Config, Peer, ReceiveMessage, SendMessage}; 15 | //! 16 | //! #[tokio::main] 17 | //! async fn main() { 18 | //! let addr_str = args().nth(1).expect("missing path"); 19 | //! let self_addr: SocketAddr = addr_str.parse().expect("invalid addr"); 20 | //! 21 | //! println!("START A INDEPENDENT P2P RELAY SERVER. : {}", self_addr); 22 | //! 23 | //! let mut config = Config::default(Peer::socket(self_addr)); 24 | //! config.permission = false; 25 | //! config.only_stable_data = true; 26 | //! config.db_dir = std::path::PathBuf::from("./"); 27 | //! 28 | //! let (peer_id, send, mut recv) = start(config).await.unwrap(); 29 | //! println!("peer id: {}", peer_id.to_hex()); 30 | //! 31 | //! if args().nth(2).is_some() { 32 | //! let remote_addr: SocketAddr = args().nth(2).unwrap().parse().expect("invalid addr"); 33 | //! println!("start DHT connect to remote: {}", remote_addr); 34 | //! send.send(SendMessage::Connect(Peer::socket(remote_addr))) 35 | //! .await 36 | //! .expect("channel failure"); 37 | //! } 38 | //! 39 | //! while let Some(message) = recv.recv().await { 40 | //! match message { 41 | //! ReceiveMessage::Data(..) => {} 42 | //! ReceiveMessage::Stream(..) => {} 43 | //! ReceiveMessage::StableConnect(from, ..) => { 44 | //! let _ = send 45 | //! .send(SendMessage::StableResult(0, from, false, false, vec![])) 46 | //! .await; 47 | //! } 48 | //! ReceiveMessage::ResultConnect(from, ..) => { 49 | //! let _ = send 50 | //! .send(SendMessage::StableResult(0, from, false, false, vec![])) 51 | //! .await; 52 | //! } 53 | //! ReceiveMessage::StableLeave(..) => {} 54 | //! ReceiveMessage::StableResult(..) => {} 55 | //! ReceiveMessage::Delivery(..) => {} 56 | //! ReceiveMessage::NetworkLost => {} 57 | //! ReceiveMessage::OwnConnect(..) => {} 58 | //! ReceiveMessage::OwnLeave(..) => {} 59 | //! ReceiveMessage::OwnEvent(..) => {} 60 | //! } 61 | //! } 62 | //! } 63 | //! ``` 64 | //! 65 | //! # Features 66 | //! 67 | //! - Support build a robust stable connection between two peers on the p2p network. 68 | //! - Support permissionless network. 69 | //! - Support permissioned network (distributed network). 70 | //! - DHT-based & Relay connection. 71 | //! - Diff transports: QUIC(*default*) / TCP / UDP-Based Special Protocol. 72 | 73 | #[macro_use] 74 | extern crate tracing; 75 | 76 | mod buffer; 77 | mod config; 78 | mod global; 79 | mod hole_punching; 80 | mod kad; 81 | mod lan; 82 | mod peer_list; 83 | mod server; 84 | mod session; 85 | mod session_key; 86 | 87 | pub mod primitives; 88 | pub mod transports; 89 | 90 | pub mod prelude { 91 | pub use chamomile_types::key::Key; 92 | pub use chamomile_types::message::{ 93 | DeliveryType, ReceiveMessage, SendMessage, StateRequest, StateResponse, StreamType, 94 | }; 95 | pub use chamomile_types::types::{Broadcast, PeerId, TransportType}; 96 | pub use chamomile_types::Peer; 97 | 98 | use tokio::{ 99 | fs::create_dir_all, 100 | io::Result, 101 | sync::mpsc::{self, Receiver, Sender}, 102 | }; 103 | 104 | pub use super::config::Config; 105 | use crate::primitives::STORAGE_NAME; 106 | 107 | /// new a channel for send message to the chamomile. 108 | pub fn new_send_channel() -> (Sender, Receiver) { 109 | mpsc::channel(1024) 110 | } 111 | 112 | /// new a channel for receive the chamomile message. 113 | pub fn new_receive_channel() -> (Sender, Receiver) { 114 | mpsc::channel(1024) 115 | } 116 | 117 | /// main function. start a p2p service. 118 | pub async fn start( 119 | mut config: Config, 120 | ) -> Result<(PeerId, Sender, Receiver)> { 121 | info!("start p2p service..."); 122 | 123 | let mut new_path = config.db_dir.clone(); 124 | new_path.push(STORAGE_NAME); 125 | if !new_path.exists() { 126 | create_dir_all(&new_path).await?; 127 | } 128 | config.db_dir = new_path; 129 | 130 | let (send_send, send_recv) = new_send_channel(); 131 | let (recv_send, recv_recv) = new_receive_channel(); 132 | 133 | let peer_id = super::server::start(config, recv_send, send_recv).await?; 134 | info!("start p2p ok."); 135 | 136 | Ok((peer_id, send_send, recv_recv)) 137 | } 138 | 139 | /// main function. start a p2p service with given secret key. 140 | pub async fn start_with_key( 141 | mut config: Config, 142 | key: Key, 143 | ) -> Result<(PeerId, Sender, Receiver)> { 144 | info!("start p2p service..."); 145 | let mut new_path = config.db_dir.clone(); 146 | new_path.push(STORAGE_NAME); 147 | if !new_path.exists() { 148 | create_dir_all(&new_path).await?; 149 | } 150 | config.db_dir = new_path; 151 | 152 | let (send_send, send_recv) = new_send_channel(); 153 | let (recv_send, recv_recv) = new_receive_channel(); 154 | 155 | let peer_id = super::server::start_with_key(config, recv_send, send_recv, key).await?; 156 | info!("start p2p ok."); 157 | 158 | Ok((peer_id, send_send, recv_recv)) 159 | } 160 | } 161 | -------------------------------------------------------------------------------- /chamomile/src/peer_list.rs: -------------------------------------------------------------------------------- 1 | use std::collections::HashMap; 2 | use std::io::BufRead; 3 | use std::iter::Iterator; 4 | use std::net::{IpAddr, Ipv4Addr, SocketAddr}; 5 | use std::path::PathBuf; 6 | use tokio::{fs, io::Result, sync::mpsc::Sender}; 7 | 8 | use chamomile_types::{types::new_io_error, Peer, PeerId}; 9 | 10 | use crate::kad::{DoubleKadTree, KadValue}; 11 | use crate::session::SessionMessage; 12 | use crate::transports::EndpointMessage; 13 | 14 | /// PeerList. 15 | /// contains: dhts(KadTree) & stables(HashMap) 16 | pub(crate) struct PeerList { 17 | save_path: PathBuf, 18 | allows: Vec, 19 | blocks: (Vec, Vec), 20 | 21 | /// PeerId => KadValue(Sender, Sender, Peer) 22 | dhts: DoubleKadTree, 23 | /// PeerId => KadValue(Sender, Sender, Peer) 24 | stables: HashMap, 25 | /// Own assist-ids 26 | owns: Vec, 27 | } 28 | 29 | impl PeerList { 30 | pub async fn save(&self) { 31 | let mut file_string = String::new(); 32 | for addr in &self.allows { 33 | if addr.effective_socket() { 34 | file_string = format!("{}\n{}", file_string, addr.to_multiaddr_string()); 35 | } 36 | } 37 | let _ = fs::write(&self.save_path, file_string).await; 38 | } 39 | 40 | pub fn load( 41 | peer_id: PeerId, 42 | assist_id: PeerId, 43 | save_path: PathBuf, 44 | mut allows: Vec, 45 | blocks: (Vec, Vec), 46 | ) -> Self { 47 | let default_socket = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), 0); 48 | match std::fs::File::open(&save_path) { 49 | Ok(file) => { 50 | let addrs = std::io::BufReader::new(file).lines(); 51 | for addr in addrs { 52 | if let Ok(addr) = addr { 53 | if let Ok(p) = Peer::from_multiaddr_string(&addr) { 54 | let mut is_new = true; 55 | for ap in allows.iter() { 56 | if ap.socket == p.socket { 57 | is_new = false; 58 | } 59 | } 60 | if is_new { 61 | allows.push(p); 62 | } 63 | } 64 | } 65 | } 66 | PeerList { 67 | save_path, 68 | allows: allows, 69 | blocks: blocks, 70 | dhts: DoubleKadTree::new(peer_id, assist_id, default_socket), 71 | stables: HashMap::new(), 72 | owns: vec![], 73 | } 74 | } 75 | Err(_) => PeerList { 76 | save_path, 77 | allows: allows, 78 | blocks: blocks, 79 | dhts: DoubleKadTree::new(peer_id, assist_id, default_socket), 80 | stables: HashMap::new(), 81 | owns: vec![], 82 | }, 83 | } 84 | } 85 | 86 | pub fn is_empty(&self) -> bool { 87 | self.stables.is_empty() && self.dhts.is_empty() 88 | } 89 | 90 | /// get all peers in the peer list. 91 | pub fn all(&self) -> HashMap> { 92 | let mut peers: HashMap> = HashMap::new(); 93 | for key in self.dhts.keys().into_iter() { 94 | if let Some((sender, _, _)) = self.dht_get(&key) { 95 | peers.insert(key, sender); 96 | } 97 | } 98 | 99 | for (p, v) in self.stables.iter() { 100 | peers.insert(*p, &(v.0).0); 101 | } 102 | 103 | peers 104 | } 105 | 106 | pub fn dht_keys(&self) -> Vec { 107 | self.dhts.keys() 108 | } 109 | 110 | /// get all stable peers in the peer list. 111 | pub fn stable_all(&self) -> HashMap, bool)> { 112 | self.stables 113 | .iter() 114 | .map(|(k, v)| (*k, (&(v.0).0, v.1))) 115 | .collect() 116 | } 117 | 118 | /// search in stable list and DHT table. result is channel sender and if is it. 119 | pub fn get( 120 | &self, 121 | peer_id: &PeerId, 122 | ) -> Option<(&Sender, &Sender, bool)> { 123 | self.stable_get(peer_id).or(self.dht_get(peer_id)) 124 | } 125 | 126 | /// search in stable list. result is stream channel sender. 127 | pub fn get_stable_stream(&self, peer_id: &PeerId) -> Option<&Sender> { 128 | self.stable_get(peer_id) 129 | .map(|(_ss, stream, is_it)| if is_it { Some(stream) } else { None }) 130 | .flatten() 131 | } 132 | 133 | pub fn next_closest( 134 | &self, 135 | target: &PeerId, 136 | prev: &[PeerId], 137 | ) -> Option<&Sender> { 138 | self.stables 139 | .get(target) 140 | .map(|v| &(v.0).0) 141 | .or(self.dhts.id_next_closest(target, prev).map(|v| &v.0)) 142 | } 143 | 144 | pub fn _ip_next_closest( 145 | &self, 146 | ip: &SocketAddr, 147 | prev: &[SocketAddr], 148 | ) -> Option<&Sender> { 149 | self.dhts._ip_next_closest(ip, prev).map(|v| &v.0) 150 | } 151 | 152 | /// search in dht table. 153 | pub fn dht_get( 154 | &self, 155 | peer_id: &PeerId, 156 | ) -> Option<(&Sender, &Sender, bool)> { 157 | self.dhts 158 | .search(peer_id) 159 | .map(|(v, is_it)| (&v.0, &v.1, is_it)) 160 | } 161 | 162 | /// search in stable list. 163 | pub fn stable_get( 164 | &self, 165 | peer_id: &PeerId, 166 | ) -> Option<(&Sender, &Sender, bool)> { 167 | self.stables 168 | .get(peer_id) 169 | .map(|v| (&(v.0).0, &(v.0).1, true)) 170 | } 171 | 172 | /// if peer has connected in peer list. 173 | pub fn contains(&self, peer_id: &PeerId) -> bool { 174 | self.stables.contains_key(peer_id) || self.dhts.contains(peer_id) 175 | } 176 | 177 | /// check stable is relay. 178 | pub fn is_relay(&self, peer_id: &PeerId) -> Option<&Sender> { 179 | self.stables 180 | .get(peer_id) 181 | .map(|v| if !v.1 { Some(&(v.0).0) } else { None }) 182 | .flatten() 183 | } 184 | 185 | /// get in DHT help 186 | pub fn help_dht(&self, _peer_id: &PeerId) -> Vec { 187 | // TODO better closest peers 188 | 189 | let mut peers = vec![]; 190 | for (_, (_, v)) in &self.dhts.values { 191 | for va in v.iter() { 192 | peers.push(va.2); 193 | } 194 | } 195 | 196 | for (_, v) in self.stables.iter() { 197 | peers.push((v.0).2); 198 | } 199 | 200 | peers 201 | } 202 | 203 | /// Step: 204 | /// 1. remove from kad; 205 | pub fn remove_peer(&mut self, peer_id: &PeerId, assist_id: &PeerId) { 206 | self.dhts.remove(peer_id, assist_id); 207 | } 208 | 209 | /// Disconnect Step: 210 | /// 1. remove from bootstrap. 211 | pub async fn peer_disconnect(&mut self, addr: &SocketAddr) { 212 | let mut d: Option = None; 213 | for (k, i) in self.allows.iter().enumerate() { 214 | if &i.socket == addr { 215 | d = Some(k); 216 | } 217 | } 218 | 219 | if let Some(i) = d { 220 | self.allows.remove(i); 221 | self.save().await; 222 | } 223 | } 224 | 225 | /// Peer leave Step: 226 | /// 1. remove from stables. 227 | pub fn stable_leave(&mut self, peer_id: &PeerId) { 228 | self.stables.remove(peer_id); 229 | } 230 | 231 | /// Step: 232 | /// 1. add to boostraps; 233 | /// 2. add to kad. 234 | pub async fn add_dht(&mut self, v: KadValue) -> bool { 235 | // 1. add to boostraps. 236 | if v.2.is_pub && !self.allows.contains(&v.2) { 237 | self.add_bootstrap(v.2); 238 | self.save().await; 239 | } 240 | 241 | // 2. add to kad. 242 | if self.dhts.add(v) { 243 | true 244 | } else { 245 | false 246 | } 247 | } 248 | 249 | /// add inner-own device. 250 | pub fn add_own(&mut self, assist_id: PeerId, v: KadValue, is_direct: bool) { 251 | if !self.owns.contains(&assist_id) { 252 | self.owns.push(assist_id); 253 | self.add_stable(assist_id, v, is_direct); 254 | } 255 | } 256 | 257 | /// Peer stable connect ok Step: 258 | /// 1. add to bootstrap; 259 | /// 2. add to stables; 260 | pub fn add_stable(&mut self, peer_id: PeerId, v: KadValue, is_direct: bool) { 261 | match self.stables.get_mut(&peer_id) { 262 | Some((KadValue(s, ss, p), direct)) => { 263 | let _ = s.try_send(SessionMessage::Close); 264 | let KadValue(sender, stream, peer) = v; 265 | *s = sender; 266 | *ss = stream; 267 | *p = peer; 268 | *direct = is_direct; 269 | } 270 | None => { 271 | self.add_allow_peer(peer_id); 272 | self.stables.insert(peer_id, (v, is_direct)); 273 | } 274 | } 275 | } 276 | 277 | pub fn stable_to_dht(&mut self, peer_id: &PeerId) -> Result<()> { 278 | self.remove_allow_peer(peer_id); 279 | if let Some((v, is_direct)) = self.stables.remove(peer_id) { 280 | if is_direct { 281 | if self.dhts.add(v) { 282 | return Ok(()); 283 | } 284 | } 285 | } 286 | Err(new_io_error("stable is closed")) 287 | } 288 | 289 | pub fn dht_to_stable(&mut self, peer_id: &PeerId, a_id: &PeerId) -> Result<()> { 290 | if let Some(mut v) = self.dhts.take(peer_id, a_id) { 291 | // only use one in stable. 292 | if let Some(va) = v.pop() { 293 | self.add_allow_peer(*peer_id); 294 | self.stables.insert(*peer_id, (va, true)); 295 | } 296 | Ok(()) 297 | } else { 298 | Err(new_io_error("DHT is closed")) 299 | } 300 | } 301 | } 302 | 303 | // Block and allow list. 304 | impl PeerList { 305 | pub fn own(&self) -> &[PeerId] { 306 | &self.owns 307 | } 308 | 309 | pub fn bootstrap(&self) -> Vec<&Peer> { 310 | self.allows 311 | .iter() 312 | .filter_map(|p| if p.effective_socket() { Some(p) } else { None }) 313 | .collect() 314 | } 315 | 316 | pub fn add_bootstrap(&mut self, peer: Peer) { 317 | let mut is_new = true; 318 | for ap in self.allows.iter() { 319 | if ap.socket == peer.socket { 320 | is_new = false; 321 | } 322 | } 323 | if is_new { 324 | self.allows.push(peer); 325 | } 326 | } 327 | 328 | pub fn add_allow_peer(&mut self, pid: PeerId) { 329 | let mut is_new = true; 330 | for ap in self.allows.iter() { 331 | if ap.id == pid { 332 | is_new = false; 333 | } 334 | } 335 | if is_new { 336 | self.allows.push(Peer::peer(pid)); 337 | } 338 | } 339 | 340 | pub fn remove_allow_peer(&mut self, peer: &PeerId) -> Option { 341 | let pos = match self.allows.iter().position(|x| &x.id == peer) { 342 | Some(x) => x, 343 | None => return None, 344 | }; 345 | Some(self.allows.remove(pos)) 346 | } 347 | 348 | pub fn is_block_peer(&self, peer: &PeerId) -> bool { 349 | self.blocks.0.contains(peer) 350 | } 351 | 352 | pub fn is_block_addr(&self, addr: &SocketAddr) -> bool { 353 | self.blocks.1.contains(&addr.ip()) 354 | } 355 | 356 | pub fn _add_block_peer(&mut self, peer: PeerId) { 357 | if !self.blocks.0.contains(&peer) { 358 | self.blocks.0.push(peer) 359 | } 360 | } 361 | 362 | pub fn _add_block_addr(&mut self, addr: SocketAddr) { 363 | if !self.blocks.1.contains(&addr.ip()) { 364 | self.blocks.1.push(addr.ip()) 365 | } 366 | } 367 | 368 | pub fn _remove_block_peer(&mut self, peer: &PeerId) -> Option { 369 | let pos = match self.blocks.0.iter().position(|x| *x == *peer) { 370 | Some(x) => x, 371 | None => return None, 372 | }; 373 | Some(self.blocks.0.remove(pos)) 374 | } 375 | 376 | pub fn _remove_block_addr(&mut self, addr: &SocketAddr) -> Option { 377 | let pos = match self.blocks.1.iter().position(|x| *x == addr.ip()) { 378 | Some(x) => x, 379 | None => return None, 380 | }; 381 | Some(self.blocks.1.remove(pos)) 382 | } 383 | } 384 | -------------------------------------------------------------------------------- /chamomile/src/primitives.rs: -------------------------------------------------------------------------------- 1 | pub const STORAGE_NAME: &'static str = "p2p"; 2 | 3 | pub const STORAGE_KEY_KEY: &'static str = "key"; 4 | 5 | pub const STORAGE_ASSIST: &'static str = "assist"; 6 | 7 | pub const STORAGE_PEER_LIST_KEY: &'static str = "peer_list"; 8 | -------------------------------------------------------------------------------- /chamomile/src/server.rs: -------------------------------------------------------------------------------- 1 | use rand_chacha::{ 2 | rand_core::{RngCore, SeedableRng}, 3 | ChaChaRng, 4 | }; 5 | use std::{collections::HashMap, path::PathBuf, sync::Arc, time::Duration}; 6 | use tokio::{ 7 | fs, 8 | io::Result, 9 | select, 10 | sync::mpsc::{Receiver, Sender}, 11 | sync::RwLock, 12 | time::interval, 13 | }; 14 | 15 | use chamomile_types::{ 16 | delivery_split, 17 | key::Key, 18 | message::{DeliveryType, ReceiveMessage, SendMessage, StateRequest, StateResponse}, 19 | types::{Broadcast, PeerId, TransportType, PEER_ID_LENGTH}, 20 | Peer, 21 | }; 22 | 23 | use crate::buffer::{Buffer, BufferKey}; 24 | use crate::config::Config; 25 | use crate::global::Global; 26 | use crate::hole_punching::{nat, DHT}; 27 | use crate::kad::KadValue; 28 | use crate::peer_list::PeerList; 29 | use crate::primitives::{STORAGE_ASSIST, STORAGE_KEY_KEY, STORAGE_PEER_LIST_KEY}; 30 | use crate::session::{ 31 | direct_stable, new_session_channel, relay_stable, session_spawn, ConnectType, Session, 32 | SessionMessage, 33 | }; 34 | use crate::transports::{ 35 | start as transport_start, EndpointMessage, RemotePublic, TransportRecvMessage, 36 | TransportSendMessage, 37 | }; 38 | 39 | async fn get_keypair(mut key_path: PathBuf) -> Key { 40 | key_path.push(STORAGE_KEY_KEY); 41 | 42 | let key_bytes = fs::read(&key_path).await.unwrap_or(vec![]); // safe. 43 | let key = match Key::from_db_bytes(&key_bytes) { 44 | Ok(keypair) => keypair, 45 | Err(_) => { 46 | let key = Key::generate(&mut ChaChaRng::from_entropy()); 47 | let key_bytes = key.to_db_bytes(); 48 | let _ = fs::write(key_path, key_bytes).await; 49 | key 50 | } 51 | }; 52 | 53 | key 54 | } 55 | 56 | async fn get_assist(mut path: PathBuf) -> PeerId { 57 | path.push(STORAGE_ASSIST); 58 | let bytes = fs::read(&path).await.unwrap_or(vec![]); // safe. 59 | let mut id_bytes = [0u8; PEER_ID_LENGTH]; 60 | 61 | if bytes.len() == PEER_ID_LENGTH { 62 | id_bytes.copy_from_slice(&bytes); 63 | PeerId(id_bytes) 64 | } else { 65 | let rng = &mut ChaChaRng::from_entropy(); 66 | rng.fill_bytes(&mut id_bytes); 67 | let _ = fs::write(path, id_bytes).await; 68 | PeerId(id_bytes) 69 | } 70 | } 71 | 72 | pub async fn start( 73 | config: Config, 74 | out_sender: Sender, 75 | self_receiver: Receiver, 76 | ) -> Result { 77 | let key = get_keypair(config.db_dir.clone()).await; 78 | start_with_key(config, out_sender, self_receiver, key).await 79 | } 80 | 81 | async fn start_bootstrap_peers( 82 | config: Config, 83 | out_sender: Sender, 84 | key: Key, 85 | ) -> (Arc, Receiver) { 86 | let peer_id = key.peer_id(); 87 | 88 | let Config { 89 | db_dir, 90 | mut peer, 91 | mut allowlist, 92 | blocklist, 93 | allow_peer_list, 94 | block_peer_list, 95 | permission, 96 | only_stable_data: _, 97 | delivery_length, 98 | } = config; 99 | 100 | allowlist.extend(allow_peer_list.iter().map(|pid| Peer::peer(*pid))); 101 | 102 | peer.id = peer_id; 103 | peer.assist = get_assist(db_dir.clone()).await; 104 | debug!("P2P ID: {} - {}", peer.id.to_hex(), peer.assist.to_hex()); 105 | 106 | let mut peer_list_path = db_dir; 107 | peer_list_path.push(STORAGE_PEER_LIST_KEY); 108 | let peer_list = Arc::new(RwLock::new(PeerList::load( 109 | peer_id, 110 | peer.assist, 111 | peer_list_path, 112 | allowlist, 113 | (block_peer_list, blocklist), 114 | ))); 115 | 116 | let mut transports: HashMap> = HashMap::new(); 117 | 118 | let (local_addr, trans_send, trans_option, main_option) = transport_start(&peer, None) 119 | .await 120 | .expect("Transport binding failure!"); 121 | let trans_recv = trans_option.unwrap(); // safe 122 | let main_trans = main_option.unwrap(); // safe 123 | 124 | peer.socket = local_addr; 125 | transports.insert(peer.transport, trans_send.clone()); 126 | 127 | let global = Arc::new(Global { 128 | peer, 129 | key, 130 | out_sender, 131 | delivery_length, 132 | trans: main_trans, 133 | transports: Arc::new(RwLock::new(transports)), 134 | buffer: Arc::new(RwLock::new(Buffer::init())), 135 | peer_list: peer_list.clone(), 136 | is_relay_data: !permission, 137 | }); 138 | 139 | // bootstrap allow list. 140 | for a in peer_list.read().await.bootstrap() { 141 | let (session_key, remote_pk) = global.generate_remote(); 142 | let _ = global 143 | .trans_send( 144 | &a.transport, 145 | TransportSendMessage::Connect(a.socket, remote_pk, session_key), 146 | ) 147 | .await; 148 | } 149 | 150 | (global, trans_recv) 151 | } 152 | 153 | /// start server 154 | pub async fn start_with_key( 155 | config: Config, 156 | out_sender: Sender, 157 | mut self_receiver: Receiver, 158 | key: Key, 159 | ) -> Result { 160 | let peer_id = key.peer_id(); 161 | 162 | let (global, mut trans_recv) = start_bootstrap_peers(config.clone(), out_sender, key).await; 163 | 164 | let only_stable_data = config.only_stable_data; 165 | let delivery_length = config.delivery_length; 166 | 167 | let recv_data = !only_stable_data; 168 | let inner_global = global.clone(); 169 | let listen_task = tokio::spawn(async move { 170 | enum FutureResult { 171 | Trans(TransportRecvMessage), 172 | Clear, 173 | Check, 174 | } 175 | 176 | // Check Timer: every 10s to check network. (read only). 177 | let mut check_interval = interval(Duration::from_secs(10)); 178 | 179 | // Clear Timer: every 60s to check buffer. 180 | let mut clear_interval = interval(Duration::from_secs(60)); 181 | 182 | loop { 183 | let futres = select! { 184 | v = async { 185 | trans_recv.recv().await.map(|msg| FutureResult::Trans(msg)) 186 | } => v, 187 | v = async { 188 | check_interval.tick().await; 189 | Some(FutureResult::Check) 190 | } => v, 191 | v = async { 192 | clear_interval.tick().await; 193 | Some(FutureResult::Clear) 194 | } => v, 195 | }; 196 | 197 | match futres { 198 | Some(FutureResult::Trans(TransportRecvMessage( 199 | addr, 200 | RemotePublic(remote_peer, dh_key), 201 | is_self, 202 | stream_sender, 203 | stream_receiver, 204 | endpoint_sender, 205 | ))) => { 206 | debug!("Incoming remote peer..."); 207 | // 1. check is block ip. 208 | if inner_global.peer_list.read().await.is_block_addr(&addr) { 209 | debug!("Incoming remote ip is blocked, close it."); 210 | let _ = endpoint_sender.send(EndpointMessage::Close).await; 211 | continue; 212 | } 213 | 214 | let remote_id = remote_peer.id; 215 | let remote_peer = nat(addr, remote_peer); 216 | debug!("Incoming remote NAT addr: {}", remote_peer.socket); 217 | 218 | // 2. check is self or is block peer. 219 | if (&remote_id == inner_global.peer_id() 220 | && &remote_peer.assist == inner_global.assist_id()) 221 | || inner_global 222 | .peer_list 223 | .read() 224 | .await 225 | .is_block_peer(&remote_id) 226 | { 227 | debug!("Incoming remote peer is blocked, close it."); 228 | let _ = endpoint_sender.send(EndpointMessage::Close).await; 229 | continue; 230 | } 231 | 232 | // 3. check session key and send self info to remote. 233 | let session_key = if let Some(mut session_key) = is_self { 234 | if session_key.complete(&remote_id, dh_key) { 235 | session_key 236 | } else { 237 | debug!("Incoming remote session key is invalid, close it."); 238 | let _ = endpoint_sender.send(EndpointMessage::Close).await; 239 | continue; 240 | } 241 | } else { 242 | if let Some((session_key, remote_pk)) = 243 | inner_global.complete_remote(&remote_id, dh_key) 244 | { 245 | let _ = endpoint_sender 246 | .send(EndpointMessage::Handshake(remote_pk)) 247 | .await; 248 | session_key 249 | } else { 250 | debug!("Incoming remote session key is invalid, close it."); 251 | let _ = endpoint_sender.send(EndpointMessage::Close).await; 252 | continue; 253 | } 254 | }; 255 | 256 | // 4. check is stable relay connections. 257 | if let Some(ss) = inner_global.peer_list.read().await.is_relay(&remote_id) { 258 | debug!("Incoming remote upgrade to direct."); 259 | let _ = ss 260 | .send(SessionMessage::DirectIncoming( 261 | remote_peer, 262 | stream_sender, 263 | stream_receiver, 264 | endpoint_sender, 265 | )) 266 | .await; 267 | continue; 268 | } 269 | 270 | // 5. save to DHTs or Owns. 271 | let (session_sender, session_receiver) = new_session_channel(); 272 | let kv = KadValue(session_sender.clone(), stream_sender, remote_peer); 273 | 274 | let is_own = &remote_id == inner_global.peer_id(); 275 | if is_own { 276 | inner_global 277 | .peer_list 278 | .write() 279 | .await 280 | .add_own(remote_peer.assist, kv, true); 281 | } else { 282 | let is_new = inner_global.peer_list.write().await.add_dht(kv).await; 283 | // 6. check if had connected. 284 | if !is_new { 285 | debug!("Incoming remote add dht failure, close it."); 286 | let _ = endpoint_sender.send(EndpointMessage::Close).await; 287 | continue; 288 | } 289 | 290 | // 7. DHT help. 291 | let peers = inner_global.peer_list.read().await.help_dht(&remote_id); 292 | let _ = endpoint_sender.send(EndpointMessage::DHT(DHT(peers))).await; 293 | } 294 | 295 | session_spawn( 296 | Session::new( 297 | remote_peer, 298 | session_sender, 299 | stream_receiver, 300 | ConnectType::Direct(endpoint_sender), 301 | session_key, 302 | inner_global.clone(), 303 | is_own || recv_data, 304 | is_own, 305 | ), 306 | session_receiver, 307 | ); 308 | debug!("Incoming remote sessioned: {}.", remote_id.short_show()); 309 | } 310 | Some(FutureResult::Check) => { 311 | if inner_global.peer_list.read().await.is_empty() { 312 | let _ = inner_global.out_send(ReceiveMessage::NetworkLost).await; 313 | } 314 | } 315 | Some(FutureResult::Clear) => { 316 | inner_global.buffer.write().await.timer_clear().await; 317 | } 318 | None => break, 319 | } 320 | } 321 | }); 322 | 323 | tokio::spawn(async move { 324 | loop { 325 | match self_receiver.recv().await { 326 | Some(SendMessage::StableConnect(tid, to, data)) => { 327 | debug!("Outside: StableConnect to {}.", to.id.short_show()); 328 | if &to.id == global.peer_id() { 329 | warn!("CHAMOMILE: STABLE CONNECT NERVER TO SELF."); 330 | if tid != 0 { 331 | let _ = global 332 | .out_send(ReceiveMessage::Delivery( 333 | DeliveryType::StableConnect, 334 | tid, 335 | false, 336 | delivery_split!(data, delivery_length), 337 | )) 338 | .await; 339 | } 340 | continue; 341 | } 342 | 343 | // check peer is not effective and addr is effective 344 | if !to.effective_id() && to.effective_socket() { 345 | debug!("Outside: StableConnect start new connection with IP."); 346 | let delivery = delivery_split!(data, global.delivery_length); 347 | 348 | // add to stable buffer. 349 | let mut buffer_lock = global.buffer.write().await; 350 | if buffer_lock.add_connect(BufferKey::Addr(to.socket), tid, data) { 351 | debug!("Outside: StableConnect is processing, save to buffer."); 352 | drop(buffer_lock); 353 | continue; 354 | } 355 | drop(buffer_lock); 356 | 357 | let g = global.clone(); 358 | tokio::spawn(async move { 359 | let _ = direct_stable(tid, delivery, to, g, recv_data, false).await; 360 | }); 361 | continue; 362 | } 363 | 364 | // 1. get it or closest peer. 365 | let peer_list_lock = global.peer_list.read().await; 366 | let results = peer_list_lock.get(&to.id); 367 | if results.is_none() { 368 | drop(peer_list_lock); 369 | warn!("CHAMOMILE: CANNOT REACH NETWORK."); 370 | if tid != 0 { 371 | let _ = global 372 | .out_send(ReceiveMessage::Delivery( 373 | DeliveryType::StableConnect, 374 | tid, 375 | false, 376 | delivery_split!(data, delivery_length), 377 | )) 378 | .await; 379 | } 380 | continue; 381 | } 382 | 383 | // 2. if connected, send to remote. 384 | let (s, _, is_it) = results.unwrap(); // safe checked. 385 | if is_it { 386 | debug!("Outside: StableConnect multiple stable connected."); 387 | let _ = s.send(SessionMessage::StableConnect(tid, data)).await; 388 | drop(peer_list_lock); 389 | } else { 390 | let ss = s.clone(); 391 | drop(peer_list_lock); 392 | 393 | // 3. check if had in buffer tmp. 394 | if let Some(sender) = global.buffer.read().await.get_tmp_session(&to.id) { 395 | debug!("Outside: StableConnect is in tmp, send to it."); 396 | let _ = sender.send(SessionMessage::StableConnect(tid, data)).await; 397 | continue; 398 | } 399 | 400 | // 4. add to stable buffer. 401 | let mut buffer_lock = global.buffer.write().await; 402 | let delivery = delivery_split!(data, global.delivery_length); 403 | if buffer_lock.add_connect(BufferKey::Peer(to.id), tid, data) { 404 | debug!("Outside: StableConnect is processing, save to buffer."); 405 | drop(buffer_lock); 406 | continue; 407 | } 408 | drop(buffer_lock); 409 | 410 | let g = global.clone(); 411 | if to.effective_socket() { 412 | debug!("Outside: StableConnect start new connection with IP."); 413 | tokio::spawn(async move { 414 | let _ = direct_stable(tid, delivery, to, g, recv_data, false).await; 415 | }); 416 | } else { 417 | debug!("Outside: StableConnect start new connection with ID."); 418 | tokio::spawn(async move { 419 | let _ = 420 | relay_stable(tid, delivery, to, ss, g, recv_data, false).await; 421 | }); 422 | } 423 | } 424 | } 425 | Some(SendMessage::StableResult(tid, to, is_ok, is_force, data)) => { 426 | debug!("Outside: StableResult to {}.", to.id.short_show()); 427 | if &to.id == global.peer_id() { 428 | warn!("CHAMOMILE: STABLE CONNECT NERVER TO SELF."); 429 | if tid != 0 { 430 | let _ = global 431 | .out_send(ReceiveMessage::Delivery( 432 | DeliveryType::StableResult, 433 | tid, 434 | false, 435 | delivery_split!(data, delivery_length), 436 | )) 437 | .await; 438 | } 439 | continue; 440 | } 441 | 442 | // 1. check if in tmp. 443 | if let Some(sender) = global.buffer.read().await.get_tmp_session(&to.id) { 444 | debug!("Outside: StableResult get the tmp session."); 445 | let _ = sender 446 | .send(SessionMessage::StableResult(tid, is_ok, is_force, data)) 447 | .await; 448 | continue; 449 | } 450 | 451 | // 2. check if in DHT or stable. 452 | let peer_list_lock = global.peer_list.read().await; 453 | let results = peer_list_lock.get(&to.id); 454 | if results.is_none() { 455 | drop(peer_list_lock); 456 | warn!("CHAMOMILE: CANNOT REACH NETWORK."); 457 | if tid != 0 { 458 | let _ = global 459 | .out_send(ReceiveMessage::Delivery( 460 | DeliveryType::StableResult, 461 | tid, 462 | false, 463 | delivery_split!(data, delivery_length), 464 | )) 465 | .await; 466 | } 467 | continue; 468 | } 469 | 470 | let (s, _, is_it) = results.unwrap(); // safe checked. 471 | if is_it { 472 | debug!("Outside: StableResult get the is_it session."); 473 | let _ = s 474 | .send(SessionMessage::StableResult(tid, is_ok, is_force, data)) 475 | .await; 476 | drop(peer_list_lock); 477 | } else { 478 | // 3. check if is_ok, if ok, start stable connected. 479 | if !is_ok { 480 | drop(peer_list_lock); 481 | continue; 482 | } 483 | 484 | let ss = s.clone(); 485 | drop(peer_list_lock); 486 | 487 | // 4. check if had in buffer tmp. 488 | if let Some(sender) = global.buffer.read().await.get_tmp_session(&to.id) { 489 | debug!("Outside: StableResult had tmp session."); 490 | let _ = sender 491 | .send(SessionMessage::StableResult(tid, is_ok, is_force, data)) 492 | .await; 493 | continue; 494 | } 495 | 496 | // 5. add to stable buffer. 497 | let delivery = delivery_split!(data, global.delivery_length); 498 | let mut buffer_lock = global.buffer.write().await; 499 | if buffer_lock.add_result(to.id, tid, data) { 500 | debug!("Outside: StableResult is processing, save to buffer."); 501 | drop(buffer_lock); 502 | continue; 503 | } 504 | drop(buffer_lock); 505 | 506 | let g = global.clone(); 507 | debug!("Outside: StableResult start new connection with ID."); 508 | if to.effective_socket() { 509 | tokio::spawn(async move { 510 | let _ = direct_stable(tid, delivery, to, g, recv_data, false).await; 511 | }); 512 | } else { 513 | tokio::spawn(async move { 514 | let _ = 515 | relay_stable(tid, delivery, to, ss, g, recv_data, false).await; 516 | }); 517 | } 518 | } 519 | } 520 | Some(SendMessage::StableDisconnect(pid)) => { 521 | debug!("Outside: StableDisconnect to {}.", pid.short_show()); 522 | if let Some((sender, _, is_it)) = global.peer_list.read().await.get(&pid) { 523 | if is_it { 524 | let _ = sender.send(SessionMessage::Close).await; 525 | } 526 | } 527 | } 528 | Some(SendMessage::Connect(peer)) => { 529 | debug!("Outside: DHT Connect to {}.", peer.socket); 530 | let (session_key, remote_pk) = global.generate_remote(); 531 | let _ = global 532 | .trans_send( 533 | &peer.transport, 534 | TransportSendMessage::Connect(peer.socket, remote_pk, session_key), 535 | ) 536 | .await; 537 | } 538 | Some(SendMessage::DisConnect(peer)) => { 539 | debug!("Outside: DHT Disconnect to {}.", peer.socket); 540 | global 541 | .peer_list 542 | .write() 543 | .await 544 | .peer_disconnect(&peer.socket) 545 | .await; 546 | } 547 | Some(SendMessage::Data(tid, to, data)) => { 548 | // check if send to self. better circle for application. 549 | if &to == global.peer_id() { 550 | warn!("CHAMOMILE: Data to self. PLEASE use SendMessage::OwnEvent."); 551 | if tid != 0 { 552 | let _ = global 553 | .out_send(ReceiveMessage::Delivery( 554 | DeliveryType::Data, 555 | tid, 556 | true, 557 | delivery_split!(data, delivery_length), 558 | )) 559 | .await; 560 | } 561 | let _ = global.out_send(ReceiveMessage::Data(to, data)).await; 562 | continue; 563 | } 564 | 565 | if let Some((sender, _, is_it)) = global.peer_list.read().await.get(&to) { 566 | if is_it { 567 | let _ = sender.send(SessionMessage::Data(tid, data)).await; 568 | } else { 569 | // only happen on permissionless. 570 | let _ = sender 571 | .send(SessionMessage::RelayData(*global.peer_id(), to, data)) 572 | .await; 573 | } 574 | } else { 575 | warn!("CHAMOMILE: CANNOT REACH NETWORK."); 576 | if tid != 0 { 577 | let _ = global 578 | .out_send(ReceiveMessage::Delivery( 579 | DeliveryType::Data, 580 | tid, 581 | false, 582 | delivery_split!(data, delivery_length), 583 | )) 584 | .await; 585 | } 586 | } 587 | } 588 | Some(SendMessage::Broadcast(broadcast, data)) => match broadcast { 589 | Broadcast::StableAll => { 590 | for (_to, (sender, _)) in global.peer_list.read().await.stable_all() { 591 | let _ = sender.send(SessionMessage::Data(0, data.clone())).await; 592 | } 593 | } 594 | Broadcast::Gossip => { 595 | // TODO more Gossip base on Kad. 596 | for (_to, sender) in global.peer_list.read().await.all() { 597 | let _ = sender.send(SessionMessage::Data(0, data.clone())).await; 598 | } 599 | } 600 | }, 601 | Some(SendMessage::OwnEvent(data)) => { 602 | let peer_list = global.peer_list.read().await; 603 | for pid in peer_list.own() { 604 | if let Some((sender, _, is_it)) = peer_list.get(&pid) { 605 | if is_it { 606 | let _ = sender.send(SessionMessage::Data(0, data.clone())).await; 607 | } 608 | } 609 | } 610 | } 611 | Some(SendMessage::Stream(_symbol, _stream_type, _data)) => { 612 | // TODO WIP 613 | } 614 | Some(SendMessage::NetworkState(req, res_sender)) => match req { 615 | StateRequest::Stable => { 616 | let peers = global 617 | .peer_list 618 | .read() 619 | .await 620 | .stable_all() 621 | .iter() 622 | .map(|(id, (_, is_direct))| (*id, *is_direct)) 623 | .collect(); 624 | let _ = res_sender.send(StateResponse::Stable(peers)).await; 625 | } 626 | StateRequest::DHT => { 627 | let peers = global.peer_list.read().await.dht_keys(); 628 | let _ = res_sender.send(StateResponse::DHT(peers)).await; 629 | } 630 | StateRequest::Seed => { 631 | let seeds = global 632 | .peer_list 633 | .read() 634 | .await 635 | .bootstrap() 636 | .iter() 637 | .map(|p| **p) 638 | .collect(); 639 | let _ = res_sender.send(StateResponse::Seed(seeds)).await; 640 | } 641 | }, 642 | Some(SendMessage::NetworkReboot) => { 643 | // rebootstrap allow list. 644 | for a in global.peer_list.read().await.bootstrap() { 645 | let (session_key, remote_pk) = global.generate_remote(); 646 | let _ = global 647 | .trans_send( 648 | &a.transport, 649 | TransportSendMessage::Connect(a.socket, remote_pk, session_key), 650 | ) 651 | .await; 652 | } 653 | } 654 | Some(SendMessage::NetworkStop) => { 655 | // clear all sessions 656 | for (_, sender) in global.peer_list.read().await.all() { 657 | let _ = sender.send(SessionMessage::Close).await; 658 | } 659 | 660 | // clear all transports. 661 | for (_, sender) in global.transports.read().await.iter() { 662 | let _ = sender.send(TransportSendMessage::Stop).await; 663 | } 664 | 665 | listen_task.abort(); 666 | break; 667 | } 668 | None => break, 669 | } 670 | } 671 | }); 672 | 673 | Ok(peer_id) 674 | } 675 | -------------------------------------------------------------------------------- /chamomile/src/session_key.rs: -------------------------------------------------------------------------------- 1 | use aes_gcm::aead::{generic_array::GenericArray, Aead}; 2 | use aes_gcm::{Aes256Gcm, KeyInit}; 3 | use chamomile_types::{ 4 | key::secp256k1::{PublicKey, Secp256k1, SecretKey}, 5 | key::{Key, Signature, PUBLIC_KEY_LENGTH, SIGNATURE_LENGTH}, 6 | types::{new_io_error, PeerId}, 7 | }; 8 | use rand_chacha::{rand_core::SeedableRng, ChaChaRng}; 9 | use std::io::Result; 10 | 11 | //#[derive(Zeroize)] 12 | pub struct SessionKey { 13 | /// Random secret key for this session 14 | sk: SecretKey, 15 | /// The session key is success 16 | is_ok: bool, 17 | /// 256-bit key (random key from DH key) 18 | cipher: Aes256Gcm, 19 | } 20 | 21 | /// Simple DH on 25519 to get AES-256 session key. 22 | /// 1. new a tmp public_key and sign it. 23 | /// 2. send tmp public key and signature to remote. 24 | /// 2. receive remote tmp public_key and signature, verify it. 25 | /// 3. use remote public_key and self tmp private key to compute. 26 | /// 4. get session key, and encrypt / decrypt message. 27 | impl SessionKey { 28 | pub fn is_ok(&self) -> bool { 29 | self.is_ok 30 | } 31 | 32 | pub fn generate(key: &Key) -> (SessionKey, Vec) { 33 | let mut rng = ChaChaRng::from_entropy(); 34 | let sk = SecretKey::new(&mut rng); 35 | let pk = sk.public_key(&Secp256k1::new()); 36 | let mut pk_bytes = pk.serialize().to_vec(); 37 | let sign = key.sign(&pk_bytes); 38 | pk_bytes.extend(sign.to_bytes()); 39 | 40 | ( 41 | SessionKey { 42 | sk, 43 | is_ok: false, 44 | cipher: Aes256Gcm::new(GenericArray::from_slice(&[0u8; 32])), 45 | }, 46 | pk_bytes, 47 | ) 48 | } 49 | 50 | pub fn generate_complete( 51 | key: &Key, 52 | id: &PeerId, 53 | dh_bytes: Vec, 54 | ) -> Option<(SessionKey, Vec)> { 55 | let (mut session, bytes) = Self::generate(key); 56 | if session.complete(id, dh_bytes) { 57 | Some((session, bytes)) 58 | } else { 59 | None 60 | } 61 | } 62 | 63 | pub fn complete(&mut self, id: &PeerId, remote_dh: Vec) -> bool { 64 | // pk_bytes (33) + sign_bytes (68) 65 | if remote_dh.len() != PUBLIC_KEY_LENGTH + SIGNATURE_LENGTH { 66 | return false; 67 | } 68 | 69 | let (tmp_pk, tmp_sign) = remote_dh.split_at(PUBLIC_KEY_LENGTH); 70 | match ( 71 | PublicKey::from_slice(tmp_pk), 72 | Signature::from_bytes(tmp_sign), 73 | ) { 74 | (Ok(pk), Ok(sign)) => { 75 | if let Ok(new_id) = sign.peer_id(tmp_pk) { 76 | if new_id != *id { 77 | return false; 78 | } 79 | if let Ok(dh) = pk.mul_tweak(&Secp256k1::new(), &self.sk.into()) { 80 | self.cipher = 81 | Aes256Gcm::new(GenericArray::from_slice(&dh.serialize()[0..32])); 82 | self.is_ok = true; 83 | return true; 84 | } 85 | } 86 | } 87 | _ => {} 88 | } 89 | 90 | false 91 | } 92 | 93 | pub fn encrypt(&self, msg: Vec) -> Vec { 94 | let nonce = GenericArray::from_slice(&[0u8; 12]); 95 | self.cipher.encrypt(&nonce, msg.as_ref()).unwrap_or(vec![]) 96 | } 97 | 98 | pub fn decrypt(&self, msg: Vec) -> Result> { 99 | let nonce = GenericArray::from_slice(&[0u8; 12]); 100 | self.cipher 101 | .decrypt(&nonce, msg.as_ref()) 102 | .map_err(|_e| new_io_error("decrypt failure.")) 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /chamomile/src/transports.rs: -------------------------------------------------------------------------------- 1 | use std::io::Result; 2 | use std::net::SocketAddr; 3 | use tokio::sync::mpsc::{self, Receiver, Sender}; 4 | 5 | use chamomile_types::{ 6 | peer::{Peer, PEER_LENGTH}, 7 | types::{new_io_error, PeerId, TransportType, PEER_ID_LENGTH}, 8 | }; 9 | 10 | mod rtp; 11 | mod tcp; 12 | //mod udp; 13 | mod quic; 14 | mod udt; 15 | 16 | use crate::hole_punching::{Hole, DHT}; 17 | use crate::session_key::SessionKey; 18 | 19 | /// waiting for connect time 20 | pub const CONNECTING_WAITING: u64 = 60; // 60s 21 | 22 | /// new a channel for send TransportSendMessage. 23 | pub fn new_transport_send_channel() -> (Sender, Receiver) 24 | { 25 | mpsc::channel(1024) 26 | } 27 | 28 | /// new a channel for receive EndpointIncomingMessage. 29 | pub fn new_transport_recv_channel() -> (Sender, Receiver) 30 | { 31 | mpsc::channel(1024) 32 | } 33 | 34 | /// new a channel for EndpointSendMessage between in session's and transport stream. 35 | pub fn new_endpoint_channel() -> (Sender, Receiver) { 36 | mpsc::channel(1024) 37 | } 38 | 39 | /// Endpoint can receied this message channel. 40 | pub enum TransportSendMessage { 41 | /// connect to a socket address. 42 | /// params is `socket_addr`, `remote_pk bytes`. 43 | Connect(SocketAddr, RemotePublic, SessionKey), 44 | /// params is `delivery_id`, `socket_addr`, `remote_pk bytes`. 45 | StableConnect( 46 | Sender, 47 | Receiver, 48 | SocketAddr, 49 | RemotePublic, 50 | ), 51 | Stop, 52 | } 53 | 54 | /// when endpoint get a incoming connection, will send to outside. 55 | /// params: `socket_addr`, `endpoint_stream_receiver`, 56 | /// `endpoint_stream_sender` and `is_stable`, `remote_pk bytes`. 57 | pub struct TransportRecvMessage( 58 | pub SocketAddr, // remote addr. 59 | pub RemotePublic, // remote public info. 60 | pub Option, // is send by self and the send session_key. 61 | pub Sender, // session's endpoint sender. 62 | pub Receiver, // session's endpoint receiver. 63 | pub Sender, // transport's receiver. 64 | ); 65 | 66 | /// Session Endpoint Message. 67 | /// bytes[0] is type, bytes[1..] is data. 68 | pub enum EndpointMessage { 69 | /// type is 0u8. 70 | Close, 71 | /// type is 1u8. 72 | Handshake(RemotePublic), 73 | /// type is 2u8. 74 | DHT(DHT), 75 | /// type is 3u8. 76 | Hole(Hole), 77 | /// type is 4u8. 78 | HoleConnect, 79 | /// type is 5u8. encrypted's CoreData. 80 | Data(Vec), 81 | /// type is 6u8. Relay Handshake. 82 | RelayHandshake(RemotePublic, PeerId), 83 | /// type is 7u8. encrypted's CoreData. 84 | RelayData(PeerId, PeerId, Vec), 85 | } 86 | 87 | /// main function. start the endpoint listening. 88 | pub async fn start( 89 | peer: &Peer, 90 | out_send: Option>, 91 | ) -> Result<( 92 | SocketAddr, 93 | Sender, 94 | Option>, 95 | Option>, 96 | )> { 97 | let both = out_send.is_none(); 98 | let (send_send, send_recv) = new_transport_send_channel(); 99 | let (recv_send, recv_recv, main_out) = if let Some(out_send) = out_send { 100 | (out_send, None, None) 101 | } else { 102 | let (recv_send, recv_recv) = new_transport_recv_channel(); 103 | (recv_send.clone(), Some(recv_recv), Some(recv_send)) 104 | }; 105 | 106 | let local_addr = match peer.transport { 107 | //&TransportType::UDP => udp::UdpEndpoint::start(addr, recv_send, send_recv).await?, 108 | TransportType::TCP => tcp::start(peer.socket, recv_send, send_recv, both).await?, 109 | TransportType::QUIC => quic::start(peer.socket, recv_send, send_recv, both).await?, 110 | _ => panic!("Not suppert, waiting"), 111 | }; 112 | 113 | Ok((local_addr, send_send, recv_recv, main_out)) 114 | } 115 | 116 | /// Rtemote Public Info, include local transport and public key bytes, session_key out_bytes. 117 | pub struct RemotePublic(pub Peer, pub Vec); 118 | 119 | impl RemotePublic { 120 | pub fn id(&self) -> &PeerId { 121 | &self.0.id 122 | } 123 | 124 | pub fn assist(&self) -> &PeerId { 125 | &self.0.assist 126 | } 127 | 128 | pub fn from_bytes(mut bytes: Vec) -> Result { 129 | if bytes.len() < PEER_LENGTH + 2 { 130 | return Err(new_io_error("Remote bytes failure.")); 131 | } 132 | let peer = Peer::from_bytes(bytes.drain(0..PEER_LENGTH).as_slice())?; 133 | Ok(Self(peer, bytes)) 134 | } 135 | 136 | pub fn to_bytes(mut self) -> Vec { 137 | let mut bytes = vec![]; 138 | bytes.append(&mut self.0.to_bytes()); 139 | bytes.append(&mut self.1); 140 | bytes 141 | } 142 | } 143 | 144 | impl EndpointMessage { 145 | pub fn to_bytes(self) -> Vec { 146 | let mut bytes = vec![0u8]; 147 | match self { 148 | EndpointMessage::Close => { 149 | bytes[0] = 0u8; 150 | } 151 | EndpointMessage::Handshake(peer) => { 152 | bytes[0] = 1u8; 153 | let mut peer_bytes = peer.to_bytes(); 154 | bytes.extend(&(peer_bytes.len() as u32).to_be_bytes()[..]); 155 | bytes.append(&mut peer_bytes); 156 | } 157 | EndpointMessage::DHT(dht) => { 158 | bytes[0] = 2u8; 159 | bytes.append(&mut dht.to_bytes()); 160 | } 161 | EndpointMessage::Hole(hole) => { 162 | bytes[0] = 3u8; 163 | bytes.push(hole.to_byte()); 164 | } 165 | EndpointMessage::HoleConnect => { 166 | bytes[0] = 4u8; 167 | } 168 | EndpointMessage::Data(mut data) => { 169 | bytes[0] = 5u8; 170 | bytes.append(&mut data); 171 | } 172 | EndpointMessage::RelayHandshake(p1_peer, p2_id) => { 173 | bytes[0] = 6u8; 174 | let mut peer_bytes = p1_peer.to_bytes(); 175 | bytes.extend(&(peer_bytes.len() as u32).to_be_bytes()[..]); 176 | bytes.append(&mut peer_bytes); 177 | bytes.append(&mut p2_id.to_bytes()); 178 | } 179 | EndpointMessage::RelayData(p1_id, p2_id, mut data) => { 180 | bytes[0] = 7u8; 181 | bytes.append(&mut p1_id.to_bytes()); 182 | bytes.append(&mut p2_id.to_bytes()); 183 | bytes.append(&mut data); 184 | } 185 | } 186 | 187 | bytes 188 | } 189 | 190 | fn from_bytes(mut bytes: Vec) -> Result { 191 | if bytes.len() < 1 { 192 | return Err(new_io_error("EndpointMessage bytes failure.")); 193 | } 194 | 195 | let t: Vec = bytes.drain(0..1).collect(); 196 | match t[0] { 197 | 0u8 => Ok(EndpointMessage::Close), 198 | 1u8 => { 199 | if bytes.len() < 4 { 200 | return Err(new_io_error("EndpointMessage bytes failure.")); 201 | } 202 | let mut peer_len_bytes = [0u8; 4]; 203 | peer_len_bytes.copy_from_slice(bytes.drain(0..4).as_slice()); 204 | let peer_len = u32::from_be_bytes(peer_len_bytes) as usize; 205 | if bytes.len() < peer_len { 206 | return Err(new_io_error("EndpointMessage bytes failure.")); 207 | } 208 | let peer = RemotePublic::from_bytes(bytes.drain(0..peer_len).collect()) 209 | .map_err(|_| new_io_error("EndpointMessage bytes failure."))?; 210 | Ok(EndpointMessage::Handshake(peer)) 211 | } 212 | 2u8 => { 213 | let dht = DHT::from_bytes(&bytes)?; 214 | Ok(EndpointMessage::DHT(dht)) 215 | } 216 | 3u8 => { 217 | if bytes.len() != 1 { 218 | return Err(new_io_error("EndpointMessage bytes failure.")); 219 | } 220 | let hole = Hole::from_byte(bytes[0])?; 221 | Ok(EndpointMessage::Hole(hole)) 222 | } 223 | 4u8 => Ok(EndpointMessage::HoleConnect), 224 | 5u8 => Ok(EndpointMessage::Data(bytes)), 225 | 6u8 => { 226 | if bytes.len() < 4 { 227 | return Err(new_io_error("EndpointMessage bytes failure.")); 228 | } 229 | let mut peer_len_bytes = [0u8; 4]; 230 | peer_len_bytes.copy_from_slice(bytes.drain(0..4).as_slice()); 231 | let peer_len = u32::from_be_bytes(peer_len_bytes) as usize; 232 | if bytes.len() < peer_len + PEER_ID_LENGTH { 233 | return Err(new_io_error("EndpointMessage bytes failure.")); 234 | } 235 | let peer = RemotePublic::from_bytes(bytes.drain(0..peer_len).collect()) 236 | .map_err(|_| new_io_error("EndpointMessage bytes failure."))?; 237 | let p2 = PeerId::from_bytes(&bytes.drain(0..PEER_ID_LENGTH).as_slice())?; 238 | Ok(EndpointMessage::RelayHandshake(peer, p2)) 239 | } 240 | 7u8 => { 241 | if bytes.len() < PEER_ID_LENGTH * 2 { 242 | return Err(new_io_error("EndpointMessage bytes failure.")); 243 | } 244 | let p1 = PeerId::from_bytes(&bytes.drain(0..PEER_ID_LENGTH).as_slice())?; 245 | let p2 = PeerId::from_bytes(&bytes.drain(0..PEER_ID_LENGTH).as_slice())?; 246 | Ok(EndpointMessage::RelayData(p1, p2, bytes)) 247 | } 248 | _ => Err(new_io_error("EndpointMessage bytes failure.")), 249 | } 250 | } 251 | } 252 | -------------------------------------------------------------------------------- /chamomile/src/transports/quic.rs: -------------------------------------------------------------------------------- 1 | use serde::{Deserialize, Serialize}; 2 | use socket2::Socket; 3 | use std::{ 4 | collections::HashMap, 5 | net::{SocketAddr, UdpSocket}, 6 | sync::Arc, 7 | time::{Duration, Instant}, 8 | }; 9 | use structopt::StructOpt; 10 | use tokio::sync::mpsc::{Receiver, Sender}; 11 | use tokio::{io::Result, join, select, sync::RwLock, task::JoinHandle}; 12 | 13 | use crate::session_key::SessionKey; 14 | 15 | use super::{ 16 | new_endpoint_channel, EndpointMessage, RemotePublic, TransportRecvMessage, 17 | TransportSendMessage, CONNECTING_WAITING, 18 | }; 19 | 20 | const DOMAIN: &str = "chamomile.quic"; 21 | const SIZE_LIMIT: usize = 67108864; // 64 * 1024 * 1024 = 64 MB 22 | 23 | /// Init and run a QuicEndpoint object. 24 | /// You need send a socketaddr str and quic send message's addr, 25 | /// and receiver outside message addr. 26 | pub async fn start( 27 | bind_addr: SocketAddr, 28 | send: Sender, 29 | recv: Receiver, 30 | both: bool, 31 | ) -> tokio::io::Result { 32 | let config = InternalConfig::try_from_config(Default::default()).unwrap(); 33 | 34 | let udp_socket = UdpSocket::bind(&bind_addr)?; 35 | let socket = Socket::from(udp_socket); 36 | socket.set_reuse_address(true)?; 37 | let new_udp_socket: UdpSocket = socket.into(); 38 | 39 | let endpoint = quinn::Endpoint::new( 40 | Default::default(), 41 | Some(config.server.clone()), 42 | new_udp_socket, 43 | Arc::new(quinn::TokioRuntime), 44 | ) 45 | .unwrap(); 46 | let addr = endpoint.local_addr()?; 47 | info!("QUIC listening at: {:?}", addr); 48 | 49 | // QUIC listen incoming. 50 | let out_send = send.clone(); 51 | let incoming = endpoint.clone(); 52 | let task = tokio::spawn(async move { 53 | loop { 54 | match incoming.accept().await { 55 | Some(quinn_conn) => match quinn_conn.await { 56 | Ok(conn) => { 57 | if both { 58 | let (self_sender, self_receiver) = new_endpoint_channel(); 59 | let (out_sender, out_receiver) = new_endpoint_channel(); 60 | 61 | tokio::spawn(process_stream( 62 | conn, 63 | out_sender, 64 | self_receiver, 65 | OutType::DHT(out_send.clone(), self_sender, out_receiver), 66 | None, 67 | None, 68 | )); 69 | } 70 | } 71 | Err(err) => { 72 | error!("An incoming failed because of an error: {:?}", err); 73 | } 74 | }, 75 | None => { 76 | break; 77 | } 78 | } 79 | } 80 | }); 81 | 82 | // QUIC listen from outside. 83 | tokio::spawn(run_self_recv(endpoint, config.client, recv, send, task)); 84 | 85 | Ok(addr) 86 | } 87 | 88 | async fn connect_to( 89 | connect: std::result::Result, 90 | remote_pk: RemotePublic, 91 | ) -> Result { 92 | let conn = connect 93 | .map_err(|_| std::io::Error::new(std::io::ErrorKind::Other, "connecting failure."))? 94 | .await?; 95 | let mut stream = conn.open_uni().await?; 96 | stream 97 | .write_all(&EndpointMessage::Handshake(remote_pk).to_bytes()) 98 | .await?; 99 | stream.finish().await?; 100 | Ok(conn) 101 | } 102 | 103 | async fn dht_connect_to( 104 | connect: std::result::Result, 105 | out_send: Sender, 106 | remote_pk: RemotePublic, 107 | session_key: SessionKey, 108 | connectiongs: Arc>>, 109 | ) -> Result<()> { 110 | let conn = connect_to(connect, remote_pk).await?; 111 | let (self_sender, self_receiver) = new_endpoint_channel(); 112 | let (out_sender, out_receiver) = new_endpoint_channel(); 113 | 114 | process_stream( 115 | conn, 116 | out_sender, 117 | self_receiver, 118 | OutType::DHT(out_send, self_sender, out_receiver), 119 | Some(session_key), 120 | Some(connectiongs), 121 | ) 122 | .await 123 | } 124 | 125 | async fn stable_connect_to( 126 | connect: std::result::Result, 127 | out_sender: Sender, 128 | self_receiver: Receiver, 129 | remote_pk: RemotePublic, 130 | connectiongs: Arc>>, 131 | ) -> Result<()> { 132 | match connect_to(connect, remote_pk).await { 133 | Ok(conn) => { 134 | process_stream( 135 | conn, 136 | out_sender, 137 | self_receiver, 138 | OutType::Stable, 139 | None, 140 | Some(connectiongs), 141 | ) 142 | .await 143 | } 144 | Err(_) => { 145 | let _ = out_sender.send(EndpointMessage::Close).await; 146 | Ok(()) 147 | } 148 | } 149 | } 150 | 151 | async fn run_self_recv( 152 | endpoint: quinn::Endpoint, 153 | client_cfg: quinn::ClientConfig, 154 | mut recv: Receiver, 155 | out_send: Sender, 156 | task: JoinHandle<()>, 157 | ) -> Result<()> { 158 | let connecting: Arc>> = 159 | Arc::new(RwLock::new(HashMap::new())); 160 | 161 | while let Some(m) = recv.recv().await { 162 | match m { 163 | TransportSendMessage::Connect(addr, remote_pk, session_key) => { 164 | let read_lock = connecting.read().await; 165 | if let Some(time) = read_lock.get(&addr) { 166 | if time.elapsed().as_secs() < CONNECTING_WAITING { 167 | drop(read_lock); 168 | continue; 169 | } 170 | } 171 | drop(read_lock); 172 | let mut lock = connecting.write().await; 173 | lock.insert(addr, Instant::now()); 174 | drop(lock); 175 | 176 | let connect = endpoint.connect_with(client_cfg.clone(), addr, DOMAIN); 177 | info!("QUIC dht connect to: {:?}", addr); 178 | tokio::spawn(dht_connect_to( 179 | connect, 180 | out_send.clone(), 181 | remote_pk, 182 | session_key, 183 | connecting.clone(), 184 | )); 185 | } 186 | TransportSendMessage::StableConnect(out_sender, self_receiver, addr, remote_pk) => { 187 | let read_lock = connecting.read().await; 188 | if let Some(time) = read_lock.get(&addr) { 189 | if time.elapsed().as_secs() < CONNECTING_WAITING { 190 | drop(read_lock); 191 | continue; 192 | } 193 | } 194 | drop(read_lock); 195 | let mut lock = connecting.write().await; 196 | lock.insert(addr, Instant::now()); 197 | drop(lock); 198 | 199 | let connect = endpoint.connect_with(client_cfg.clone(), addr, DOMAIN); 200 | info!("QUIC stable connect to: {:?}", addr); 201 | tokio::spawn(stable_connect_to( 202 | connect, 203 | out_sender, 204 | self_receiver, 205 | remote_pk, 206 | connecting.clone(), 207 | )); 208 | } 209 | TransportSendMessage::Stop => { 210 | task.abort(); 211 | endpoint.close(0u8.into(), &[]); 212 | break; 213 | } 214 | } 215 | } 216 | 217 | Ok(()) 218 | } 219 | 220 | enum OutType { 221 | DHT( 222 | Sender, 223 | Sender, 224 | Receiver, 225 | ), 226 | Stable, 227 | } 228 | 229 | async fn process_stream( 230 | conn: quinn::Connection, 231 | out_sender: Sender, 232 | mut self_receiver: Receiver, 233 | out_type: OutType, 234 | has_session: Option, 235 | connectiongs: Option>>>, 236 | ) -> tokio::io::Result<()> { 237 | let addr = conn.remote_address(); 238 | 239 | let handshake: std::result::Result = select! { 240 | v = async { 241 | match conn.accept_uni().await { 242 | Err(quinn::ConnectionError::ApplicationClosed { .. }) => { 243 | debug!("Connection terminated by peer {:?}.", addr); 244 | Err(()) 245 | } 246 | Err(err) => { 247 | debug!( 248 | "Failed to read incoming message on uni-stream for peer {:?} with error: {:?}", 249 | addr, err 250 | ); 251 | Err(()) 252 | } 253 | Ok(mut recv) => { 254 | if let Ok(bytes) = recv.read_to_end(SIZE_LIMIT).await { 255 | if let Ok(EndpointMessage::Handshake(remote_pk)) = 256 | EndpointMessage::from_bytes(bytes) 257 | { 258 | return Ok(remote_pk); 259 | } else { 260 | Err(()) 261 | } 262 | } else { 263 | Err(()) 264 | } 265 | } 266 | } 267 | } => v, 268 | v = async { 269 | tokio::time::sleep(std::time::Duration::from_secs(10)).await; 270 | Err(()) 271 | } => v 272 | }; 273 | 274 | if handshake.is_err() { 275 | // close it. if is_by_self, Better send outside not connect. 276 | debug!("Transport: connect read publics timeout, close it."); 277 | return Ok(()); 278 | } 279 | 280 | let remote_pk = handshake.unwrap(); // safe. checked. 281 | 282 | match out_type { 283 | OutType::Stable => { 284 | out_sender 285 | .send(EndpointMessage::Handshake(remote_pk)) 286 | .await 287 | .map_err(|_e| { 288 | std::io::Error::new(std::io::ErrorKind::Other, "endpoint channel missing") 289 | })?; 290 | } 291 | OutType::DHT(sender, self_sender, out_receiver) => { 292 | sender 293 | .send(TransportRecvMessage( 294 | addr, 295 | remote_pk, 296 | has_session, 297 | out_sender.clone(), 298 | out_receiver, 299 | self_sender, 300 | )) 301 | .await 302 | .map_err(|_e| { 303 | std::io::Error::new(std::io::ErrorKind::Other, "server channel missing") 304 | })?; 305 | } 306 | } 307 | 308 | if let Some(connectiongs) = connectiongs { 309 | let mut lock = connectiongs.write().await; 310 | lock.remove(&addr); 311 | drop(lock); 312 | drop(connectiongs); 313 | } 314 | 315 | let conn_send = conn.clone(); 316 | let a = async move { 317 | loop { 318 | match self_receiver.recv().await { 319 | Some(msg) => { 320 | let mut writer = conn_send.open_uni().await.map_err(|_e| ())?; 321 | let is_close = match msg { 322 | EndpointMessage::Close => true, 323 | _ => false, 324 | }; 325 | 326 | let _ = writer.write_all(&msg.to_bytes()).await; 327 | let _ = writer.finish().await; 328 | 329 | if is_close { 330 | break; 331 | } 332 | } 333 | None => break, 334 | } 335 | } 336 | 337 | Err::<(), ()>(()) 338 | }; 339 | 340 | let b = async { 341 | loop { 342 | match conn.accept_uni().await { 343 | Err(quinn::ConnectionError::ApplicationClosed { .. }) => { 344 | debug!("Connection terminated by peer {:?}.", addr); 345 | break; 346 | } 347 | Err(err) => { 348 | debug!( 349 | "Failed to read incoming message on uni-stream for peer {:?} with error: {:?}", 350 | addr, err 351 | ); 352 | break; 353 | } 354 | Ok(mut recv) => { 355 | if let Ok(bytes) = recv.read_to_end(SIZE_LIMIT).await { 356 | if let Ok(msg) = EndpointMessage::from_bytes(bytes) { 357 | let _ = out_sender.send(msg).await; 358 | } 359 | } 360 | } 361 | } 362 | } 363 | }; 364 | 365 | let _ = join!(a, b); 366 | 367 | info!("close stream: {}", addr); 368 | conn.close(0u8.into(), &[]); 369 | Ok(()) 370 | } 371 | 372 | /// Default for [`Config::idle_timeout`] (5s). 373 | /// 374 | /// This is based on average time in which routers would close the UDP mapping to the peer if they 375 | /// see no conversation between them. 376 | pub const DEFAULT_IDLE_TIMEOUT: Duration = Duration::from_secs(5); 377 | 378 | /// Quic configurations 379 | #[derive(Clone, Debug, Default, Serialize, Deserialize, Eq, PartialEq, StructOpt)] 380 | pub struct Config { 381 | /// Specify if port forwarding via UPnP should be done or not. This can be set to false if the network 382 | /// is run locally on the network loopback or on a local area network. 383 | //#[structopt(long)] 384 | //pub forward_port: bool, 385 | 386 | /// External port number assigned to the socket address of the program. 387 | /// If this is provided, QP2p considers that the local port provided has been mapped to the 388 | /// provided external port number and automatic port forwarding will be skipped. 389 | //#[structopt(long)] 390 | //pub external_port: Option, 391 | 392 | /// External IP address of the computer on the WAN. This field is mandatory if the node is the genesis node and 393 | /// port forwarding is not available. In case of non-genesis nodes, the external IP address will be resolved 394 | /// using the Echo service. 395 | //#[structopt(long)] 396 | //pub external_ip: Option, 397 | 398 | /// How long to wait to hear from a peer before timing out a connection. 399 | /// 400 | /// In the absence of any keep-alive messages, connections will be closed if they remain idle 401 | /// for at least this duration. 402 | /// 403 | /// If unspecified, this will default to [`DEFAULT_IDLE_TIMEOUT`]. 404 | #[serde(default)] 405 | #[structopt(long, parse(try_from_str = parse_millis), value_name = "MILLIS")] 406 | pub idle_timeout: Option, 407 | } 408 | 409 | fn parse_millis(millis: &str) -> std::result::Result { 410 | Ok(Duration::from_millis(millis.parse()?)) 411 | } 412 | 413 | /// Config that has passed validation. 414 | /// 415 | /// Generally this is a copy of [`Config`] without optional values where we would use defaults. 416 | #[derive(Clone, Debug)] 417 | pub(crate) struct InternalConfig { 418 | pub(crate) client: quinn::ClientConfig, 419 | pub(crate) server: quinn::ServerConfig, 420 | //pub(crate) forward_port: bool, 421 | //pub(crate) external_port: Option, 422 | //pub(crate) external_ip: Option, 423 | } 424 | 425 | impl InternalConfig { 426 | pub(crate) fn try_from_config(config: Config) -> Result { 427 | let idle_timeout = 428 | quinn::IdleTimeout::try_from(config.idle_timeout.unwrap_or(DEFAULT_IDLE_TIMEOUT)) 429 | .map_err(|_e| { 430 | std::io::Error::new(std::io::ErrorKind::Other, "rcgen generate failure.") 431 | })?; 432 | 433 | let mut tconfig = quinn::TransportConfig::default(); 434 | let _ = tconfig.max_idle_timeout(Some(idle_timeout)); 435 | let transport = Arc::new(tconfig); 436 | 437 | let client = Self::new_client_config(transport.clone()); 438 | let server = Self::new_server_config(transport)?; 439 | 440 | Ok(Self { 441 | client, 442 | server, 443 | //forward_port: config.forward_port, 444 | //external_port: config.external_port, 445 | //external_ip: config.external_ip, 446 | }) 447 | } 448 | 449 | fn new_client_config(transport: Arc) -> quinn::ClientConfig { 450 | let mut client_crypto = rustls::ClientConfig::builder() 451 | .with_safe_defaults() 452 | .with_root_certificates(rustls::RootCertStore::empty()) 453 | .with_no_client_auth(); 454 | 455 | client_crypto 456 | .dangerous() 457 | .set_certificate_verifier(Arc::new(SkipCertificateVerification)); 458 | 459 | let mut config = quinn::ClientConfig::new(Arc::new(client_crypto)); 460 | config.transport_config(transport); 461 | config 462 | } 463 | 464 | fn new_server_config(transport: Arc) -> Result { 465 | let (cert, key) = Self::generate_cert()?; 466 | 467 | let server_crypto = rustls::ServerConfig::builder() 468 | .with_safe_defaults() 469 | .with_no_client_auth() 470 | .with_single_cert(vec![cert], key) 471 | .map_err(|_e| { 472 | std::io::Error::new(std::io::ErrorKind::Other, "server config failure.") 473 | })?; 474 | let mut config = quinn::ServerConfig::with_crypto(Arc::new(server_crypto)); 475 | config.transport = transport; 476 | Ok(config) 477 | } 478 | 479 | fn generate_cert() -> Result<(rustls::Certificate, rustls::PrivateKey)> { 480 | let cert = rcgen::generate_simple_self_signed(vec![DOMAIN.to_string()]).map_err(|_e| { 481 | std::io::Error::new(std::io::ErrorKind::Other, "rcgen generate failure.") 482 | })?; 483 | 484 | let cert_der = cert.serialize_der().map_err(|_e| { 485 | std::io::Error::new(std::io::ErrorKind::Other, "cert serialize failure.") 486 | })?; 487 | let key_der = cert.serialize_private_key_der(); 488 | 489 | Ok((rustls::Certificate(cert_der), rustls::PrivateKey(key_der))) 490 | } 491 | } 492 | 493 | struct SkipCertificateVerification; 494 | 495 | impl rustls::client::ServerCertVerifier for SkipCertificateVerification { 496 | fn verify_server_cert( 497 | &self, 498 | _: &rustls::Certificate, 499 | _: &[rustls::Certificate], 500 | _: &rustls::ServerName, 501 | _: &mut dyn Iterator, 502 | _: &[u8], 503 | _: std::time::SystemTime, 504 | ) -> std::result::Result { 505 | Ok(rustls::client::ServerCertVerified::assertion()) 506 | } 507 | } 508 | -------------------------------------------------------------------------------- /chamomile/src/transports/rtp.rs: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /chamomile/src/transports/tcp.rs: -------------------------------------------------------------------------------- 1 | use std::{collections::HashMap, net::SocketAddr, sync::Arc, time::Instant}; 2 | use tokio::{ 3 | io::{AsyncReadExt, AsyncWriteExt, Result}, 4 | join, 5 | net::{TcpListener, TcpStream}, 6 | select, 7 | sync::{ 8 | mpsc::{Receiver, Sender}, 9 | RwLock, 10 | }, 11 | task::JoinHandle, 12 | }; 13 | 14 | use crate::session_key::SessionKey; 15 | 16 | use super::{ 17 | new_endpoint_channel, EndpointMessage, RemotePublic, TransportRecvMessage, 18 | TransportSendMessage, CONNECTING_WAITING, 19 | }; 20 | 21 | /// Init and run a TcpEndpoint object. 22 | /// You need send a socketaddr str and tcp send message's addr, 23 | /// and receiver outside message addr. 24 | pub async fn start( 25 | bind_addr: SocketAddr, 26 | send: Sender, 27 | recv: Receiver, 28 | both: bool, 29 | ) -> Result { 30 | let (addr, task) = if both { 31 | let listener = TcpListener::bind(bind_addr).await.map_err(|e| { 32 | error!("TCP listen {:?}", e); 33 | std::io::Error::new(std::io::ErrorKind::Other, "TCP Listen") 34 | })?; 35 | let addr = listener.local_addr()?; 36 | info!("TCP listening at: {:?}", addr); 37 | 38 | // TCP listen incoming. 39 | let task = tokio::spawn(run_listen(listener, send.clone())); 40 | (addr, Some(task)) 41 | } else { 42 | (bind_addr, None) 43 | }; 44 | 45 | // TCP listen from outside. 46 | tokio::spawn(run_self_recv(recv, send, task)); 47 | 48 | Ok(addr) 49 | } 50 | 51 | async fn run_listen(listener: TcpListener, out_send: Sender) -> Result<()> { 52 | loop { 53 | let (stream, _) = listener.accept().await?; 54 | let (self_sender, self_receiver) = new_endpoint_channel(); 55 | let (out_sender, out_receiver) = new_endpoint_channel(); 56 | 57 | tokio::spawn(process_stream( 58 | stream, 59 | out_sender, 60 | self_receiver, 61 | OutType::DHT(out_send.clone(), self_sender, out_receiver), 62 | None, 63 | None, 64 | )); 65 | } 66 | } 67 | 68 | async fn run_self_recv( 69 | mut recv: Receiver, 70 | out_send: Sender, 71 | task: Option>>, 72 | ) -> Result<()> { 73 | let connecting: Arc>> = 74 | Arc::new(RwLock::new(HashMap::new())); 75 | 76 | while let Some(m) = recv.recv().await { 77 | match m { 78 | TransportSendMessage::Connect(addr, remote_pk, session_key) => { 79 | let read_lock = connecting.read().await; 80 | if let Some(time) = read_lock.get(&addr) { 81 | if time.elapsed().as_secs() < CONNECTING_WAITING { 82 | drop(read_lock); 83 | continue; 84 | } 85 | } 86 | drop(read_lock); 87 | let mut lock = connecting.write().await; 88 | lock.insert(addr, Instant::now()); 89 | drop(lock); 90 | let new_connecting = connecting.clone(); 91 | 92 | let server_send = out_send.clone(); 93 | tokio::spawn(async move { 94 | if let Ok(mut stream) = TcpStream::connect(addr).await { 95 | info!("TCP connect to {:?}", addr); 96 | let bytes = EndpointMessage::Handshake(remote_pk).to_bytes(); 97 | let _ = stream.write(&(bytes.len() as u32).to_be_bytes()).await; 98 | let _ = stream.write_all(&bytes[..]).await; 99 | 100 | let (self_sender, self_receiver) = new_endpoint_channel(); 101 | let (out_sender, out_receiver) = new_endpoint_channel(); 102 | 103 | let _ = process_stream( 104 | stream, 105 | out_sender, 106 | self_receiver, 107 | OutType::DHT(server_send, self_sender, out_receiver), 108 | Some(session_key), 109 | Some(new_connecting), 110 | ) 111 | .await; 112 | } else { 113 | info!("TCP cannot connect to {:?}", addr); 114 | } 115 | }); 116 | } 117 | TransportSendMessage::StableConnect(out_sender, self_receiver, addr, remote_pk) => { 118 | let read_lock = connecting.read().await; 119 | if let Some(time) = read_lock.get(&addr) { 120 | if time.elapsed().as_secs() < CONNECTING_WAITING { 121 | drop(read_lock); 122 | continue; 123 | } 124 | } 125 | drop(read_lock); 126 | let mut lock = connecting.write().await; 127 | lock.insert(addr, Instant::now()); 128 | drop(lock); 129 | let new_connecting = connecting.clone(); 130 | 131 | tokio::spawn(async move { 132 | if let Ok(mut stream) = TcpStream::connect(addr).await { 133 | info!("TCP stable connect to {:?}", addr); 134 | let bytes = EndpointMessage::Handshake(remote_pk).to_bytes(); 135 | let _ = stream.write(&(bytes.len() as u32).to_be_bytes()).await; 136 | let _ = stream.write_all(&bytes[..]).await; 137 | 138 | let _ = process_stream( 139 | stream, 140 | out_sender, 141 | self_receiver, 142 | OutType::Stable, 143 | None, 144 | Some(new_connecting), 145 | ) 146 | .await; 147 | } else { 148 | info!("TCP cannot stable connect to {:?}", addr); 149 | let _ = out_sender.send(EndpointMessage::Close).await; 150 | } 151 | }); 152 | } 153 | TransportSendMessage::Stop => { 154 | if let Some(task) = task { 155 | task.abort(); 156 | } 157 | break; 158 | } 159 | } 160 | } 161 | 162 | Ok(()) 163 | } 164 | 165 | enum OutType { 166 | DHT( 167 | Sender, 168 | Sender, 169 | Receiver, 170 | ), 171 | Stable, 172 | } 173 | 174 | async fn process_stream( 175 | mut stream: TcpStream, 176 | out_sender: Sender, 177 | mut self_receiver: Receiver, 178 | out_type: OutType, 179 | has_session: Option, 180 | connectiongs: Option>>>, 181 | ) -> Result<()> { 182 | let addr = stream.peer_addr()?; 183 | let (mut reader, mut writer) = stream.split(); 184 | 185 | let mut read_len = [0u8; 4]; 186 | let handshake: std::result::Result = select! { 187 | v = async { 188 | match reader.read(&mut read_len).await { 189 | Ok(size) => { 190 | if size != 4 { 191 | return Err(()); 192 | } 193 | 194 | let len: usize = u32::from_be_bytes(read_len) as usize; 195 | let mut read_bytes = vec![0u8; len]; 196 | let mut received: usize = 0; 197 | 198 | while let Ok(bytes_size) = reader.read(&mut read_bytes[received..]).await { 199 | received += bytes_size; 200 | if received < len { 201 | continue; 202 | } 203 | 204 | if let Ok(EndpointMessage::Handshake(remote_pk)) = 205 | EndpointMessage::from_bytes(read_bytes) 206 | { 207 | return Ok(remote_pk); 208 | } else { 209 | return Err(()); 210 | } 211 | } 212 | 213 | Err(()) 214 | } 215 | Err(e) => { 216 | error!("TCP READ ERROR: {:?}", e); 217 | Err(()) 218 | } 219 | } 220 | } => v, 221 | v = async { 222 | tokio::time::sleep(std::time::Duration::from_secs(10)).await; 223 | Err(()) 224 | } => v 225 | }; 226 | 227 | if handshake.is_err() { 228 | // close it. if is_by_self, Better send outside not connect. 229 | debug!("Transport: connect read publics timeout, close it."); 230 | return Ok(()); 231 | } 232 | 233 | let remote_pk = handshake.unwrap(); // safe. checked. 234 | 235 | if let Some(connectiongs) = connectiongs { 236 | let mut lock = connectiongs.write().await; 237 | lock.remove(&addr); 238 | drop(lock); 239 | drop(connectiongs); 240 | } 241 | 242 | match out_type { 243 | OutType::Stable => { 244 | out_sender 245 | .send(EndpointMessage::Handshake(remote_pk)) 246 | .await 247 | .map_err(|_e| { 248 | std::io::Error::new(std::io::ErrorKind::Other, "endpoint channel missing") 249 | })?; 250 | } 251 | OutType::DHT(sender, self_sender, out_receiver) => { 252 | sender 253 | .send(TransportRecvMessage( 254 | addr, 255 | remote_pk, 256 | has_session, 257 | out_sender.clone(), 258 | out_receiver, 259 | self_sender, 260 | )) 261 | .await 262 | .map_err(|_e| { 263 | std::io::Error::new(std::io::ErrorKind::Other, "server channel missing") 264 | })?; 265 | } 266 | } 267 | 268 | let a = async move { 269 | loop { 270 | match self_receiver.recv().await { 271 | Some(msg) => { 272 | let is_close = match msg { 273 | EndpointMessage::Close => true, 274 | _ => false, 275 | }; 276 | 277 | let bytes = msg.to_bytes(); 278 | if writer 279 | .write(&(bytes.len() as u32).to_be_bytes()) 280 | .await 281 | .is_ok() 282 | { 283 | let _ = writer.write_all(&bytes[..]).await; 284 | } 285 | 286 | if is_close { 287 | break; 288 | } 289 | } 290 | None => break, 291 | } 292 | } 293 | 294 | Err::<(), ()>(()) 295 | }; 296 | 297 | let b = async move { 298 | let mut read_len = [0u8; 4]; 299 | let mut received: usize = 0; 300 | 301 | loop { 302 | match reader.read(&mut read_len).await { 303 | Ok(size) => { 304 | if size == 0 { 305 | // when close or better when many Ok(0) 306 | let _ = out_sender.send(EndpointMessage::Close).await; 307 | break; 308 | } 309 | 310 | let len: usize = u32::from_be_bytes(read_len) as usize; 311 | let mut read_bytes = vec![0u8; len]; 312 | while let Ok(bytes_size) = reader.read(&mut read_bytes[received..]).await { 313 | received += bytes_size; 314 | if received > len { 315 | break; 316 | } 317 | 318 | if received != len { 319 | continue; 320 | } 321 | 322 | if let Ok(msg) = EndpointMessage::from_bytes(read_bytes) { 323 | let _ = out_sender.send(msg).await; 324 | } 325 | 326 | break; 327 | } 328 | read_len = [0u8; 4]; 329 | received = 0; 330 | } 331 | Err(_e) => { 332 | let _ = out_sender.send(EndpointMessage::Close).await; 333 | break; 334 | } 335 | } 336 | } 337 | 338 | Err::<(), ()>(()) 339 | }; 340 | 341 | let _ = join!(a, b); 342 | 343 | debug!("close stream: {}", addr); 344 | 345 | Ok(()) 346 | } 347 | -------------------------------------------------------------------------------- /chamomile/src/transports/udp.rs: -------------------------------------------------------------------------------- 1 | use rand::{thread_rng, RngCore}; 2 | use smol::{ 3 | channel::{Receiver, Sender}, 4 | io::{BufReader, Result}, 5 | lock::Mutex, 6 | net::UdpSocket, 7 | prelude::*, 8 | }; 9 | use std::collections::{BTreeMap, HashMap}; 10 | use std::net::SocketAddr; 11 | use std::sync::Arc; 12 | use tokio::select; 13 | 14 | use super::{new_channel, new_stream_channel, EndpointMessage, StreamMessage}; 15 | 16 | /// 576(MTU) - 8(Head) - 20(IP) - 8(ID + Head) = 540 17 | const UDP_UINT: usize = 540; 18 | 19 | /// save splited messages buffers. 20 | type Buffers = HashMap>)>; 21 | 22 | /// UDP Endpoint. 23 | /// Provide a simple recombine and resend function. 24 | pub struct UdpEndpoint { 25 | streams: HashMap>, 26 | } 27 | 28 | // TODO how to connected 29 | // TODO how to connected verify 30 | 31 | #[async_trait] 32 | impl UdpEndpoint { 33 | /// Init and run a UdpEndpoint object. 34 | /// You need send a socketaddr str and udp send message's addr, 35 | /// and receiver outside message addr. 36 | async fn start( 37 | socket_addr: SocketAddr, 38 | out_send: Sender, 39 | ) -> Result> { 40 | let socket: Arc = Arc::new(UdpSocket::bind(socket_addr).await?); 41 | let (send, recv) = new_channel(); 42 | let endpoint = UdpEndpoint { 43 | streams: HashMap::new(), 44 | }; 45 | 46 | let m1 = Arc::new(Mutex::new(endpoint)); 47 | let m2 = m1.clone(); 48 | 49 | smol::spawn(run_self_recv(socket.clone(), recv)); 50 | smol::spawn(run_listen(socket, out_send, m2)); 51 | Ok(send) 52 | } 53 | } 54 | 55 | /// Listen for outside send job. 56 | /// Split message to buffers, if ok, send to remote. 57 | async fn run_self_recv(socket: Arc, recv: Receiver) -> Result<()> { 58 | let mut send_buffers = Buffers::new(); 59 | 60 | while let Some(m) = recv.recv().await { 61 | let peer = match m { 62 | EndpointMessage::Connect(addr, _bytes) => addr, // TODO send connect bytes 63 | EndpointMessage::Disconnect(addr) => addr, 64 | _ => return Ok(()), 65 | }; 66 | let mut bytes = vec![1]; // TODO 67 | 68 | let buffer_key = thread_rng().next_u32(); 69 | let total_size = bytes.len(); 70 | let mut new_buffer = BTreeMap::new(); 71 | let mut i = 1; 72 | loop { 73 | if bytes.len() < UDP_UINT { 74 | new_buffer.insert(i, bytes); 75 | break; 76 | } 77 | 78 | let next_bytes = bytes.split_off(UDP_UINT); 79 | new_buffer.insert(i, bytes); 80 | bytes = next_bytes; 81 | i += 1; 82 | } 83 | 84 | send_buffers.insert(buffer_key, (total_size as u32, new_buffer)); 85 | 86 | let send_tasks = send_buffers.get(&buffer_key).unwrap(); 87 | let buffer_key_bytes = buffer_key.to_be_bytes(); 88 | 89 | let mut head_bytes = [0u8; 12]; 90 | head_bytes[0..4].copy_from_slice(&buffer_key_bytes); 91 | head_bytes[8..12].copy_from_slice(&send_tasks.0.to_be_bytes()); 92 | socket.send_to(&head_bytes, peer).await?; 93 | 94 | for (k, v) in send_tasks.1.iter() { 95 | let mut bytes = [0u8; 8 + UDP_UINT]; 96 | bytes[0..4].copy_from_slice(&buffer_key_bytes); 97 | bytes[4..8].copy_from_slice(&k.to_be_bytes()); 98 | bytes[8..8 + v.len()].copy_from_slice(v); 99 | socket.send_to(&bytes[..8 + v.len()], peer).await?; 100 | } 101 | 102 | let mut tail_bytes = [255u8; 8]; 103 | tail_bytes[0..4].copy_from_slice(&buffer_key_bytes); 104 | socket.send_to(&tail_bytes, peer).await?; 105 | } 106 | 107 | drop(send_buffers); 108 | Ok(()) 109 | } 110 | 111 | /// UDP listen. If receive bytes, handle it. 112 | /// Handle receiver bytes, first check if bytes is completed. 113 | /// If not completed, save to buffers, and waiting. 114 | /// If timeout, send request to remote, call send again or drop it. 115 | /// If completed. send to outside. 116 | async fn run_listen( 117 | socket: Arc, 118 | send: Sender, 119 | endpoint: Arc>, 120 | ) -> Result<()> { 121 | let mut recv_buffers = Buffers::new(); 122 | 123 | let mut buf = vec![0u8; 8 + UDP_UINT]; 124 | while let Ok((n, peer)) = socket.recv_from(&mut buf).await { 125 | if buf.len() < 8 { 126 | continue; 127 | } 128 | 129 | let id = bytes_to_u32(&buf[0..4]); 130 | 131 | // start new id. and save length 132 | if buf[4..8] == [0u8; 4] { 133 | if buf.len() < 12 { 134 | continue; 135 | } 136 | 137 | let total_size = bytes_to_u32(&buf[8..12]); 138 | recv_buffers 139 | .entry(id) 140 | .and_modify(|(size, _)| { 141 | *size = total_size; 142 | }) 143 | .or_insert((total_size, Default::default())); 144 | continue; 145 | } 146 | 147 | // end id 148 | if buf[4..8] == [255u8; 4] { 149 | // TODO check if all data received 150 | 151 | if let Some((_total_size, body)) = recv_buffers.remove(&id) { 152 | let data: Vec> = body.iter().map(|(_, v)| v).cloned().collect(); 153 | let data = data.concat(); 154 | let endpoint = endpoint.lock().await; 155 | if endpoint.streams.contains_key(&peer) { 156 | endpoint 157 | .streams 158 | .get(&peer) 159 | .unwrap() 160 | .send(StreamMessage::Bytes(data)) 161 | .await; 162 | } 163 | 164 | // clear buf 165 | } 166 | continue; 167 | } 168 | 169 | let no = bytes_to_u32(&buf[4..8]); 170 | recv_buffers 171 | .entry(id) 172 | .and_modify(|(_, body)| { 173 | body.insert(no, buf[8..n].to_vec()); 174 | }) 175 | .or_insert((0, { 176 | let mut body = BTreeMap::new(); 177 | body.insert(no, buf[8..n].to_vec()); 178 | body 179 | })); 180 | } 181 | 182 | drop(recv_buffers); 183 | Ok(()) 184 | } 185 | 186 | fn bytes_to_u32(buf: &[u8]) -> u32 { 187 | let mut id_bytes = [0u8; 4]; 188 | id_bytes.copy_from_slice(buf); 189 | u32::from_be_bytes(id_bytes) 190 | } 191 | -------------------------------------------------------------------------------- /chamomile/src/transports/udt.rs: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /types/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chamomile_types" 3 | version.workspace = true 4 | edition.workspace = true 5 | authors.workspace = true 6 | repository.workspace = true 7 | categories.workspace = true 8 | keywords.workspace = true 9 | description.workspace = true 10 | license.workspace = true 11 | 12 | [dependencies] 13 | hex.workspace = true 14 | rand_core.workspace = true 15 | sha3.workspace = true 16 | secp256k1.workspace = true 17 | serde.workspace = true 18 | tokio.workspace = true 19 | -------------------------------------------------------------------------------- /types/README.md: -------------------------------------------------------------------------------- 1 | Chamomile types. 2 | -------------------------------------------------------------------------------- /types/src/key.rs: -------------------------------------------------------------------------------- 1 | use rand_core::{CryptoRng, RngCore}; 2 | use secp256k1::{ 3 | constants::ONE, 4 | ecdsa::{RecoverableSignature, RecoveryId}, 5 | Message as SecpMessage, PublicKey as SecpPublicKey, Secp256k1, SecretKey as SecpSecretKey, 6 | }; 7 | use sha3::{Digest, Keccak256}; 8 | 9 | pub use secp256k1; 10 | 11 | use crate::types::{new_io_error, PeerId, PEER_ID_LENGTH}; 12 | 13 | pub const SECRET_KEY_LENGTH: usize = 32; 14 | pub const PUBLIC_KEY_LENGTH: usize = 33; 15 | pub const SIGNATURE_LENGTH: usize = 65; 16 | 17 | /// Public Key 18 | #[derive(Clone)] 19 | pub struct PublicKey(SecpPublicKey); 20 | 21 | /// Secret Key 22 | pub struct SecretKey(SecpSecretKey); 23 | 24 | pub struct Signature(RecoverableSignature); 25 | 26 | /// The keypair, include pk, sk, address 27 | pub struct Key { 28 | pub pub_key: PublicKey, 29 | pub sec_key: SecretKey, 30 | } 31 | 32 | impl Key { 33 | pub fn from_sec_key(sec_key: SecretKey) -> Self { 34 | let secp = Secp256k1::new(); 35 | let pub_key = PublicKey(sec_key.0.public_key(&secp)); 36 | 37 | Self { pub_key, sec_key } 38 | } 39 | 40 | pub fn default() -> Self { 41 | let sec_key = SecretKey(SecpSecretKey::from_slice(&ONE).unwrap()); 42 | Self::from_sec_key(sec_key) 43 | } 44 | 45 | pub fn generate(rng: &mut R) -> Key { 46 | let sec_key = SecretKey(SecpSecretKey::new(rng)); 47 | Self::from_sec_key(sec_key) 48 | } 49 | 50 | pub fn peer_id(&self) -> PeerId { 51 | self.pub_key.peer_id() 52 | } 53 | 54 | pub fn public(&self) -> PublicKey { 55 | self.pub_key.clone() 56 | } 57 | 58 | pub fn sign(&self, msg: &[u8]) -> Signature { 59 | let mut hasher = Keccak256::new(); 60 | hasher.update(msg); 61 | let result = hasher.finalize(); 62 | let msg = SecpMessage::from_digest(result.into()); 63 | let secp = Secp256k1::new(); 64 | let sign = secp.sign_ecdsa_recoverable(&msg, &self.sec_key.0); 65 | Signature(sign) 66 | } 67 | 68 | pub fn sign_eth(&self, message: &[u8]) -> Signature { 69 | const PREFIX: &str = "\x19Ethereum Signed Message:\n"; 70 | 71 | let len = message.len(); 72 | let len_string = len.to_string(); 73 | 74 | let mut eth_message = Vec::with_capacity(PREFIX.len() + len_string.len() + len); 75 | eth_message.extend_from_slice(PREFIX.as_bytes()); 76 | eth_message.extend_from_slice(len_string.as_bytes()); 77 | eth_message.extend_from_slice(message); 78 | 79 | self.sign(ð_message) 80 | } 81 | 82 | pub fn to_db_bytes(&self) -> Vec { 83 | let mut bytes = vec![]; 84 | bytes.extend(&self.sec_key.0.secret_bytes()); 85 | bytes 86 | } 87 | 88 | pub fn from_db_bytes(bytes: &[u8]) -> std::io::Result { 89 | if bytes.len() < SECRET_KEY_LENGTH { 90 | return Err(new_io_error("keypair from db bytes failure.")); 91 | } 92 | let sec_key = SecretKey( 93 | SecpSecretKey::from_slice(&bytes[..SECRET_KEY_LENGTH]) 94 | .map_err(|_| new_io_error("secret key from db bytes failure."))?, 95 | ); 96 | Ok(Self::from_sec_key(sec_key)) 97 | } 98 | } 99 | 100 | impl PublicKey { 101 | pub fn new(pk: SecpPublicKey) -> Self { 102 | Self(pk) 103 | } 104 | 105 | pub fn raw(&self) -> &SecpPublicKey { 106 | &self.0 107 | } 108 | 109 | pub fn peer_id(&self) -> PeerId { 110 | let public_key = self.0.serialize_uncompressed(); 111 | let mut hasher = Keccak256::new(); 112 | hasher.update(&public_key[1..]); 113 | let result = hasher.finalize(); 114 | let mut bytes = [0u8; PEER_ID_LENGTH]; 115 | bytes.copy_from_slice(&result[12..]); 116 | PeerId(bytes) 117 | } 118 | } 119 | 120 | impl SecretKey { 121 | pub fn new(sk: SecpSecretKey) -> Self { 122 | Self(sk) 123 | } 124 | 125 | pub fn raw(&self) -> &SecpSecretKey { 126 | &self.0 127 | } 128 | } 129 | 130 | impl Signature { 131 | pub fn to_bytes(&self) -> Vec { 132 | let (recv, fixed) = self.0.serialize_compact(); 133 | let id = match recv { 134 | RecoveryId::Zero => 0u8, 135 | RecoveryId::One => 1u8, 136 | RecoveryId::Two => 2u8, 137 | RecoveryId::Three => 3u8, 138 | }; 139 | let mut bytes = fixed.to_vec(); 140 | bytes.push(id + 27); // Compatible with eth 141 | bytes 142 | } 143 | 144 | pub fn from_bytes(bytes: &[u8]) -> std::io::Result { 145 | let bytes_len = bytes.len(); 146 | if bytes_len != SIGNATURE_LENGTH { 147 | return Err(new_io_error("Invalid signature length")); 148 | } 149 | 150 | let id = match bytes[64] { 151 | // Case 0: raw/bare 152 | v @ 0..=26 => v % 4, 153 | // Case 2: non-eip155 v value 154 | v @ 27..=34 => (v - 27) % 4, 155 | // Case 3: eip155 V value 156 | v @ 35.. => (v - 1) % 2, 157 | }; 158 | 159 | let recv = RecoveryId::try_from(id as i32).map_err(|_| new_io_error("Invalid signature value"))?; 160 | RecoverableSignature::from_compact(&bytes[..64], recv) 161 | .map(Signature) 162 | .map_err(|_| new_io_error("Invalid signature value")) 163 | } 164 | 165 | pub fn peer_id(&self, msg: &[u8]) -> std::io::Result { 166 | let mut hasher = Keccak256::new(); 167 | hasher.update(msg); 168 | let result = hasher.finalize(); 169 | let msg = SecpMessage::from_digest(result.into()); 170 | 171 | let secp = Secp256k1::new(); 172 | let pk = secp 173 | .recover_ecdsa(&msg, &self.0) 174 | .map_err(|_| new_io_error("Invalid signature"))?; 175 | Ok(PublicKey(pk).peer_id()) 176 | } 177 | 178 | pub fn peer_id_eth(self, message: &[u8]) -> std::io::Result { 179 | const PREFIX: &str = "\x19Ethereum Signed Message:\n"; 180 | 181 | let len = message.len(); 182 | let len_string = len.to_string(); 183 | 184 | let mut eth_message = Vec::with_capacity(PREFIX.len() + len_string.len() + len); 185 | eth_message.extend_from_slice(PREFIX.as_bytes()); 186 | eth_message.extend_from_slice(len_string.as_bytes()); 187 | eth_message.extend_from_slice(message); 188 | 189 | self.peer_id(ð_message) 190 | } 191 | } 192 | 193 | impl TryFrom<&str> for PublicKey { 194 | type Error = std::io::Error; 195 | 196 | fn try_from(s: &str) -> Result { 197 | let bytes = hex::decode(s.trim_start_matches("0x")).map_err(|_| new_io_error("Invalid public key hex"))?; 198 | if bytes.len() != PUBLIC_KEY_LENGTH { 199 | return Err(new_io_error("Invalid public key length")); 200 | } 201 | Ok(PublicKey( 202 | SecpPublicKey::from_slice(&bytes) 203 | .map_err(|_| new_io_error("Invalid public key value"))?, 204 | )) 205 | } 206 | } 207 | 208 | impl ToString for PublicKey { 209 | fn to_string(&self) -> String { 210 | format!("0x{}", hex::encode(self.0.serialize())) 211 | } 212 | } 213 | 214 | impl TryFrom<&str> for SecretKey { 215 | type Error = std::io::Error; 216 | 217 | fn try_from(s: &str) -> Result { 218 | let bytes = hex::decode(s.trim_start_matches("0x")).map_err(|_| new_io_error("Invalid secret key hex"))?; 219 | if bytes.len() != SECRET_KEY_LENGTH { 220 | return Err(new_io_error("Invalid secret key length")); 221 | } 222 | Ok(SecretKey( 223 | SecpSecretKey::from_slice(&bytes) 224 | .map_err(|_| new_io_error("Invalid secret key value"))?, 225 | )) 226 | } 227 | } 228 | 229 | impl ToString for SecretKey { 230 | fn to_string(&self) -> String { 231 | format!("0x{}", hex::encode(self.0.secret_bytes())) 232 | } 233 | } 234 | 235 | impl TryFrom<&str> for Signature { 236 | type Error = std::io::Error; 237 | 238 | fn try_from(s: &str) -> Result { 239 | let bytes = hex::decode(s.trim_start_matches("0x")).map_err(|_| new_io_error("Invalid secret key hex"))?; 240 | if bytes.len() != SIGNATURE_LENGTH { 241 | return Err(new_io_error("Invalid secret key length")); 242 | } 243 | Signature::from_bytes(&bytes) 244 | } 245 | } 246 | 247 | impl ToString for Signature { 248 | fn to_string(&self) -> String { 249 | format!("0x{}", hex::encode(self.to_bytes())) 250 | } 251 | } 252 | 253 | #[cfg(test)] 254 | mod tests { 255 | use super::*; 256 | 257 | const SK_HEX: &str = "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80"; 258 | const PEER_ID_HEX: &str = "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266"; 259 | const MESSAGE: &str = "thisismessage"; 260 | const SIGN_HEX: &str = "0xff68207a1c9ea9446d77e727d230ee8e591df27d7eac17807b5231a57a44ec46213a2cb25520c51ff0b6de68914d9828ab5ee762014e92866e9e1cc8fdfe25721b"; 261 | 262 | #[test] 263 | fn test_key() { 264 | let peer_id1 = PeerId::from_hex(PEER_ID_HEX).unwrap().to_bytes(); 265 | let sk = SecretKey::try_from(SK_HEX).unwrap(); 266 | assert_eq!(sk.to_string().as_str(), SK_HEX); 267 | let key = Key::from_sec_key(sk); 268 | let peer_id = key.peer_id().to_bytes(); 269 | assert_eq!(peer_id1, peer_id); 270 | } 271 | 272 | #[test] 273 | fn test_signature() { 274 | let peer_id = PeerId::from_hex(PEER_ID_HEX).unwrap(); 275 | let key = Key::from_sec_key(SecretKey::try_from(SK_HEX).unwrap()); 276 | let sign = key.sign_eth(MESSAGE.as_bytes()); 277 | let sign_bytes = sign.to_bytes(); 278 | let sign2 = Signature::from_bytes(&sign_bytes).unwrap(); 279 | let peer_id2 = sign2.peer_id_eth(MESSAGE.as_bytes()).unwrap(); 280 | assert_eq!(peer_id, peer_id2); 281 | 282 | let sign3 = Signature::try_from(SIGN_HEX).unwrap(); 283 | assert_eq!(sign3.to_string().as_str(), SIGN_HEX); 284 | let peer_id3 = sign3.peer_id_eth(MESSAGE.as_bytes()).unwrap(); 285 | assert_eq!(peer_id, peer_id3); 286 | } 287 | } 288 | -------------------------------------------------------------------------------- /types/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub mod key; 2 | pub mod message; 3 | pub mod peer; 4 | pub mod types; 5 | 6 | pub use peer::Peer; 7 | pub use types::PeerId; 8 | 9 | /// delivery data. 10 | #[macro_export] 11 | macro_rules! delivery_split { 12 | ($data:expr, $length:expr) => { 13 | if $length == 0 { 14 | Vec::new() 15 | } else if $data.len() < $length { 16 | $data.clone() 17 | } else { 18 | $data[0..$length].to_vec() 19 | } 20 | }; 21 | } 22 | -------------------------------------------------------------------------------- /types/src/message.rs: -------------------------------------------------------------------------------- 1 | use tokio::sync::mpsc::Sender; 2 | 3 | use crate::peer::Peer; 4 | use crate::types::{Broadcast, PeerId, TransportStream}; 5 | 6 | /// Custom apply for build a stream between nodes. 7 | #[derive(Debug)] 8 | pub enum StreamType { 9 | /// request for build a stream, params is peer id, transport type and request custom info. 10 | Req(Peer), 11 | /// response for build a stream, params is is_ok, and response custom info. 12 | Res(bool), 13 | /// if response is ok, will build a stream, and return the stream to ouside. 14 | Ok(TransportStream), 15 | } 16 | 17 | /// delivery message type. 18 | #[derive(Debug, Clone)] 19 | pub enum DeliveryType { 20 | Data, 21 | StableConnect, 22 | StableResult, 23 | } 24 | 25 | /// main received message for outside channel, send from chamomile to outside. 26 | #[derive(Debug)] 27 | pub enum ReceiveMessage { 28 | /// when peer what to stable connect, send from chamomile to outside. 29 | /// params is `peer` and `connect_info`. 30 | StableConnect(Peer, Vec), 31 | /// when peer get stable connect result. 32 | /// params is `peer`, `is_ok` and `result_data`. 33 | StableResult(Peer, bool, Vec), 34 | /// when peer want to response a stable result, but the session is closed, 35 | /// if stable result is ok, then need create a result connect to sender. 36 | /// the data type is stable result data type. 37 | ResultConnect(Peer, Vec), 38 | /// when a stable connection's peer leave, 39 | /// send from chamomile to outside. 40 | /// params is `peer`. 41 | StableLeave(Peer), 42 | /// when received a data from a trusted peer, 43 | /// send to outside. 44 | /// params is `peer_id` and `data_bytes`. 45 | Data(PeerId, Vec), 46 | /// (Only stable connected) Apply for build a stream between nodes. 47 | /// params is `u32` stream symbol, and `StreamType`. 48 | Stream(u32, StreamType, Vec), 49 | /// (Only stable connected) Delivery feedback. include StableConnect, StableResult, Data. `id(u32) != 0`. 50 | Delivery(DeliveryType, u64, bool, Vec), 51 | /// when network lost all DHT network and direct stables. will tell outside. 52 | NetworkLost, 53 | /// when same PeerId peer is connected. 54 | /// this peer.id is assist_id. 55 | OwnConnect(Peer), 56 | /// when same PeerId is leaved. 57 | /// this peer.id is assist_id. 58 | OwnLeave(Peer), 59 | /// when receive same PeerId message. 60 | /// params is `assist_id` and `data_bytes`. 61 | OwnEvent(PeerId, Vec), 62 | } 63 | 64 | /// main send message for outside channel, send from outside to chamomile. 65 | #[derive(Debug)] 66 | pub enum SendMessage { 67 | /// when peer request for join, outside decide connect or not. 68 | /// params is `delivery_feedback_id`, `peer`, `is_connect`, `is_force_close`, `result info`. 69 | /// if `delivery_feedback_id = 0` will not feedback. 70 | /// if `is_connect` is true, it will add to allow directly list. 71 | /// we want to build a better network, add a `is_force_close`. 72 | /// if `is_connect` is false, but `is_force_close` if true, we 73 | /// will use this peer to build our DHT for better connection. 74 | /// if false, we will force close it. 75 | /// In general, you can example as `StableResult(0, Peer, is_ok, false, vec![])`. 76 | StableResult(u64, Peer, bool, bool, Vec), 77 | /// when need add a peer to stable connect, send to chamomile from outside. 78 | /// if success connect, will start a stable connection, and add peer to kad, stables, 79 | /// bootstraps and allowlists. if failure, will send `PeerLeave` to outside. 80 | /// params is `delivery_feedback_id`, `peer` and custom `join_info`. 81 | /// if `delivery_feedback_id = 0` will not feedback. 82 | StableConnect(u64, Peer, Vec), 83 | /// when outside want to close a stable connectioned peer. use it force close. 84 | /// params is `peer_id`. 85 | StableDisconnect(PeerId), 86 | /// (DHT connected) when outside want to connect a peer. will try connect directly. 87 | /// if connected, chamomile will add to kad and bootstrap. 88 | /// params is `Peer`. 89 | Connect(Peer), 90 | /// (DHT connected) when outside donnot want to connect peer. use it to force close. 91 | /// it will remove from kad and bootstrap list. 92 | /// params is `Peer`. 93 | DisConnect(Peer), 94 | /// when need send a data to a peer, only need know the peer_id, 95 | /// the chamomile will help you send data to there. 96 | /// params is `delivery_feedback_id`, `peer_id` and `data_bytes`. 97 | /// if `delivery_feedback_id = 0` will not feedback. 98 | Data(u64, PeerId, Vec), 99 | /// when need broadcast a data to all network, 100 | /// chamomile support some common algorithm, use it, donnot worry. 101 | /// params is `broadcast_type` and `data_bytes` 102 | Broadcast(Broadcast, Vec), 103 | /// (Only Stable connected) Apply for build a stream between nodes. 104 | /// params is `u32` stream symbol, and `StreamType`. 105 | Stream(u32, StreamType, Vec), 106 | /// Request for return the network current state info. 107 | /// params is request type, and return channel's sender (async). 108 | NetworkState(StateRequest, Sender), 109 | /// When receive `ReceiveMessage::NetworkLost`, want to reboot network, it can use. 110 | NetworkReboot, 111 | /// When want to close p2p network. 112 | NetworkStop, 113 | /// when want to broadcast message with same PeerId. 114 | OwnEvent(Vec), 115 | } 116 | 117 | /// Network state info response. 118 | #[derive(Debug, Clone)] 119 | pub enum StateRequest { 120 | Stable, 121 | DHT, 122 | Seed, 123 | } 124 | 125 | /// Network state info response. 126 | #[derive(Debug)] 127 | pub enum StateResponse { 128 | /// response is peer list and peer is relay or directly. 129 | Stable(Vec<(PeerId, bool)>), 130 | /// response is peer list. 131 | DHT(Vec), 132 | /// response is socket list. 133 | Seed(Vec), 134 | } 135 | -------------------------------------------------------------------------------- /types/src/peer.rs: -------------------------------------------------------------------------------- 1 | use rand_core::{CryptoRng, RngCore}; 2 | use std::{ 3 | fmt::{Debug, Formatter, Result as FmtResult}, 4 | io::Result, 5 | net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr}, 6 | }; 7 | 8 | use crate::types::{new_io_error, PeerId, TransportType}; 9 | 10 | // [u8; 18] 11 | fn socket_addr_to_bytes(socket: &SocketAddr) -> Vec { 12 | let ip_bytes: [u8; 16] = match socket { 13 | SocketAddr::V4(ipv4) => ipv4.ip().to_ipv6_mapped().octets(), 14 | SocketAddr::V6(ipv6) => ipv6.ip().octets(), 15 | }; 16 | let port_bytes: [u8; 2] = socket.port().to_le_bytes(); 17 | 18 | let mut bytes = vec![]; 19 | bytes.extend(&ip_bytes); 20 | bytes.extend(&port_bytes); 21 | bytes 22 | } 23 | 24 | fn socket_addr_from_bytes(bytes: &[u8]) -> Result { 25 | if bytes.len() != 18 { 26 | return Err(new_io_error("peer bytes failure.")); 27 | } 28 | let mut port_bytes = [0u8; 2]; 29 | port_bytes.copy_from_slice(&bytes[16..18]); 30 | let port = u16::from_le_bytes(port_bytes); 31 | 32 | let mut ip_bytes = [0u8; 16]; 33 | ip_bytes.copy_from_slice(&bytes[0..16]); 34 | let ipv6 = Ipv6Addr::from(ip_bytes); 35 | if let Some(ipv4) = ipv6.to_ipv4() { 36 | Ok(SocketAddr::new(IpAddr::V4(ipv4), port)) 37 | } else { 38 | Ok(SocketAddr::new(IpAddr::V6(ipv6), port)) 39 | } 40 | } 41 | 42 | #[derive(Copy, Clone, Eq, PartialEq)] 43 | pub struct Peer { 44 | pub id: PeerId, 45 | pub assist: PeerId, 46 | pub socket: SocketAddr, 47 | pub transport: TransportType, 48 | pub is_pub: bool, 49 | } 50 | 51 | // PEER_ID_LENGTH + ASSIST + SOCKET_ADDR_LENGTH + 2 = 20 + 20 + 18 + 2 = 60 52 | pub const PEER_LENGTH: usize = 60; 53 | 54 | impl Peer { 55 | /// generate assist peer id for DHT. 56 | pub fn gen_assist(&mut self, rng: &mut R) { 57 | let mut bytes = [0u8; 20]; 58 | rng.fill_bytes(&mut bytes); 59 | self.assist = PeerId(bytes); 60 | } 61 | 62 | /// create peer. 63 | pub fn new(id: PeerId, socket: SocketAddr, transport: TransportType, is_pub: bool) -> Self { 64 | Self { 65 | id, 66 | socket, 67 | transport, 68 | is_pub, 69 | assist: PeerId::default(), 70 | } 71 | } 72 | 73 | /// create peer by only socket address. 74 | pub fn socket(socket: SocketAddr) -> Self { 75 | Self { 76 | socket, 77 | id: Default::default(), 78 | transport: TransportType::QUIC, 79 | is_pub: true, 80 | assist: PeerId::default(), 81 | } 82 | } 83 | 84 | /// create peer by only peer id. 85 | pub fn peer(id: PeerId) -> Self { 86 | Self { 87 | id, 88 | socket: SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), 0), 89 | transport: TransportType::QUIC, 90 | is_pub: true, 91 | assist: PeerId::default(), 92 | } 93 | } 94 | 95 | pub fn effective(&self) -> bool { 96 | self.effective_socket() || self.effective_id() 97 | } 98 | 99 | /// check if this peer contains effective peer id. 100 | pub fn effective_id(&self) -> bool { 101 | self.id != PeerId::default() 102 | } 103 | 104 | /// check if this peer contains effective socket address. 105 | pub fn effective_socket(&self) -> bool { 106 | self.socket != SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), 0) 107 | } 108 | 109 | /// change socket port to 0, and bind generate by system. 110 | pub fn zero_port(&mut self) { 111 | self.socket.set_port(0) 112 | } 113 | 114 | pub fn from_bytes(bytes: &[u8]) -> Result { 115 | if bytes.len() != PEER_LENGTH { 116 | return Err(new_io_error("peer bytes failure.")); 117 | } 118 | 119 | let id = PeerId::from_bytes(&bytes[0..20])?; 120 | let assist = PeerId::from_bytes(&bytes[20..40])?; 121 | let socket = socket_addr_from_bytes(&bytes[40..58])?; 122 | let transport = TransportType::from_byte(bytes[58])?; 123 | let is_pub = bytes[59] == 1u8; 124 | Ok(Self { 125 | id, 126 | assist, 127 | socket, 128 | transport, 129 | is_pub, 130 | }) 131 | } 132 | pub fn to_bytes(&self) -> Vec { 133 | let mut bytes = vec![]; 134 | bytes.append(&mut self.id.to_bytes()); // 20-bytes 135 | bytes.append(&mut self.assist.to_bytes()); // 20-bytes 136 | bytes.append(&mut socket_addr_to_bytes(&self.socket)); // 18-bytes 137 | bytes.push(self.transport.to_byte()); // 1-bytes 138 | bytes.push(if self.is_pub { 1u8 } else { 0u8 }); // 1-bytes 139 | bytes 140 | } 141 | 142 | /// Enhanced multiaddr, you can import/export it. 143 | /// 1 is ip version, 144 | /// 2 is bind ip address, 145 | /// 3 is transport type, 146 | /// 4 is bind port, 147 | /// 5 is open or not, 148 | /// 6 is peer id hex encode. 149 | /// example: "/ip4/127.0.0.1/tcp/1234/false/xxxxxx" 150 | pub fn to_string<'a>(&self) -> String { 151 | let v = if self.socket.is_ipv4() { "4" } else { "6" }; 152 | 153 | format!( 154 | "/ip{}/{}/{}/{}/{}/{}", 155 | v, 156 | self.socket.ip(), 157 | self.transport.to_str(), 158 | self.socket.port(), 159 | self.is_pub, 160 | self.id.to_hex() 161 | ) 162 | } 163 | 164 | /// from string exported to peer. 165 | pub fn from_string(s: &str) -> Result { 166 | let mut ss = s.split("/"); 167 | let _ = ss.next(); // ipv4 / ipv6 168 | let ipaddr = ss 169 | .next() 170 | .ok_or(new_io_error("peer string is invalid."))? 171 | .parse() 172 | .or(Err(new_io_error("peer string is invalid.")))?; // safe 173 | let transport = TransportType::from_str(ss.next().unwrap()); // safe 174 | let port = ss 175 | .next() 176 | .ok_or(new_io_error("peer string is invalid."))? 177 | .parse() 178 | .or(Err(new_io_error("peer string is invalid.")))?; // safe 179 | let socket = SocketAddr::new(ipaddr, port); 180 | let is_pub: bool = ss 181 | .next() 182 | .ok_or(new_io_error("peer string is invalid."))? 183 | .parse() 184 | .or(Err(new_io_error("peer string is invalid.")))?; 185 | let id = PeerId::from_hex(ss.next().ok_or(new_io_error("peer string is invalid."))?)?; 186 | 187 | Ok(Self { 188 | id, 189 | is_pub, 190 | socket, 191 | transport, 192 | assist: PeerId::default(), 193 | }) 194 | } 195 | 196 | /// only load this peer by socket and transport. 197 | /// example: "/ip4/127.0.0.1/tcp/1234" 198 | pub fn from_multiaddr_string(s: &str) -> Result { 199 | let mut ss = s.split("/"); 200 | let _ = ss.next(); // skip first 201 | let _ = ss.next(); // skip ipv4 / ipv6 202 | let ipaddr = ss 203 | .next() 204 | .ok_or(new_io_error("peer string is invalid."))? 205 | .parse() 206 | .or(Err(new_io_error("peer string is invalid.")))?; // safe 207 | let transport = TransportType::from_str(ss.next().unwrap()); // safe 208 | let port = ss 209 | .next() 210 | .ok_or(new_io_error("peer string is invalid."))? 211 | .parse() 212 | .or(Err(new_io_error("peer string is invalid.")))?; // safe 213 | let socket = SocketAddr::new(ipaddr, port); 214 | 215 | Ok(Self { 216 | socket, 217 | transport, 218 | id: Default::default(), 219 | is_pub: true, 220 | assist: PeerId::default(), 221 | }) 222 | } 223 | 224 | /// Multiaddr, you can import/export it. 225 | /// 1 is ip version, 226 | /// 2 is bind ip address, 227 | /// 3 is transport type, 228 | /// 4 is bind port 229 | /// example: "/ip4/127.0.0.1/tcp/1234" 230 | pub fn to_multiaddr_string(&self) -> String { 231 | let v = if self.socket.is_ipv4() { "4" } else { "6" }; 232 | 233 | format!( 234 | "/ip{}/{}/{}/{}", 235 | v, 236 | self.socket.ip(), 237 | self.transport.to_str(), 238 | self.socket.port(), 239 | ) 240 | } 241 | } 242 | 243 | impl Default for Peer { 244 | fn default() -> Self { 245 | Self { 246 | id: PeerId::default(), 247 | socket: SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), 0), 248 | transport: TransportType::TCP, 249 | is_pub: true, 250 | assist: PeerId::default(), 251 | } 252 | } 253 | } 254 | 255 | impl Debug for Peer { 256 | fn fmt(&self, f: &mut Formatter) -> FmtResult { 257 | write!(f, "Peer: {:?} {}", self.id, self.to_multiaddr_string()) 258 | } 259 | } 260 | -------------------------------------------------------------------------------- /types/src/types.rs: -------------------------------------------------------------------------------- 1 | use serde::{Deserialize, Serialize}; 2 | use sha3::{Digest, Keccak256}; 3 | use std::fmt::{Debug, Formatter, Result as FmtResult}; 4 | use std::io::Result; 5 | use tokio::sync::mpsc::{Receiver, Sender}; 6 | 7 | #[inline] 8 | pub fn new_io_error(s: &str) -> std::io::Error { 9 | std::io::Error::new(std::io::ErrorKind::Other, s) 10 | } 11 | 12 | /// peer's network id. 13 | #[derive(Copy, Clone, Default, Eq, PartialEq, Ord, PartialOrd, Hash, Deserialize, Serialize)] 14 | pub struct PeerId(pub [u8; 20]); 15 | 16 | pub const PEER_ID_LENGTH: usize = 20; 17 | 18 | impl PeerId { 19 | pub fn short_show(&self) -> String { 20 | let s = self.to_hex(); 21 | let mut new_hex = String::new(); 22 | new_hex.push_str(&s[0..6]); 23 | new_hex.push_str("..."); 24 | new_hex.push_str(&s[s.len() - 5..]); 25 | new_hex 26 | } 27 | 28 | pub fn from_bytes(bytes: &[u8]) -> Result { 29 | if bytes.len() != PEER_ID_LENGTH { 30 | return Err(new_io_error("peer id bytes failure.")); 31 | } 32 | let mut raw = [0u8; PEER_ID_LENGTH]; 33 | raw.copy_from_slice(bytes); 34 | Ok(Self(raw)) 35 | } 36 | 37 | pub fn as_bytes(&self) -> &[u8] { 38 | &self.0 39 | } 40 | 41 | pub fn to_bytes(&self) -> Vec { 42 | self.0.to_vec() 43 | } 44 | 45 | pub fn from_hex(s: &str) -> Result { 46 | let raw = if s.starts_with("0x") { &s[2..] } else { s }; 47 | let bytes = hex::decode(raw).map_err(|_| new_io_error("Invalid hex string"))?; 48 | if bytes.len() != PEER_ID_LENGTH { 49 | return Err(new_io_error("Invalid address length")); 50 | } 51 | let mut fixed_bytes = [0u8; PEER_ID_LENGTH]; 52 | fixed_bytes.copy_from_slice(&bytes); 53 | Ok(PeerId(fixed_bytes)) 54 | } 55 | 56 | pub fn to_hex(&self) -> String { 57 | // with checksum encode 58 | let hex = hex::encode(self.0); 59 | 60 | let mut hasher = Keccak256::new(); 61 | hasher.update(hex.as_bytes()); 62 | let hash = hasher.finalize(); 63 | let check_hash = hex::encode(&hash); 64 | 65 | let mut res = String::from("0x"); 66 | for (index, byte) in hex[..PEER_ID_LENGTH * 2].chars().enumerate() { 67 | if check_hash.chars().nth(index).unwrap().to_digit(16).unwrap() > 7 { 68 | res += &byte.to_uppercase().to_string(); 69 | } else { 70 | res += &byte.to_string(); 71 | } 72 | } 73 | res 74 | } 75 | } 76 | 77 | impl Debug for PeerId { 78 | fn fmt(&self, f: &mut Formatter) -> FmtResult { 79 | write!(f, "{}", self.to_hex()) 80 | } 81 | } 82 | 83 | /// support some common broadcast algorithm. 84 | #[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)] 85 | pub enum Broadcast { 86 | Gossip, 87 | StableAll, 88 | } 89 | 90 | /// Transports types support by Endpoint. 91 | #[derive(Debug, Copy, Clone, Hash, Deserialize, Serialize, Eq, PartialEq)] 92 | pub enum TransportType { 93 | QUIC, // 0u8 94 | TCP, // 1u8 95 | RTP, // 2u8 96 | UDT, // 3u8 97 | } 98 | 99 | impl TransportType { 100 | /// transports from parse from str. 101 | pub fn from_str(s: &str) -> Self { 102 | match s { 103 | "quic" => TransportType::QUIC, 104 | "tcp" => TransportType::TCP, 105 | "rtp" => TransportType::RTP, 106 | "udt" => TransportType::UDT, 107 | _ => TransportType::QUIC, 108 | } 109 | } 110 | 111 | pub fn to_str<'a>(&self) -> &'a str { 112 | match self { 113 | TransportType::QUIC => "quic", 114 | TransportType::TCP => "tcp", 115 | TransportType::RTP => "rtp", 116 | TransportType::UDT => "udt", 117 | } 118 | } 119 | 120 | pub fn from_byte(b: u8) -> Result { 121 | match b { 122 | 0u8 => Ok(TransportType::QUIC), 123 | 1u8 => Ok(TransportType::TCP), 124 | 2u8 => Ok(TransportType::RTP), 125 | 3u8 => Ok(TransportType::UDT), 126 | _ => Err(new_io_error("transport bytes failure.")), 127 | } 128 | } 129 | 130 | pub fn to_byte(&self) -> u8 { 131 | match self { 132 | TransportType::QUIC => 0u8, 133 | TransportType::TCP => 1u8, 134 | TransportType::RTP => 2u8, 135 | TransportType::UDT => 3u8, 136 | } 137 | } 138 | } 139 | 140 | #[derive(Debug)] 141 | pub struct TransportStream { 142 | transport: TransportType, 143 | sender: Sender>, 144 | receiver: Receiver>, 145 | } 146 | 147 | impl Eq for TransportStream {} 148 | 149 | impl PartialEq for TransportStream { 150 | fn eq(&self, other: &TransportStream) -> bool { 151 | self.transport == other.transport 152 | } 153 | } 154 | 155 | impl TransportStream { 156 | pub fn new( 157 | transport: TransportType, 158 | sender: Sender>, 159 | receiver: Receiver>, 160 | ) -> Self { 161 | Self { 162 | transport, 163 | sender, 164 | receiver, 165 | } 166 | } 167 | 168 | pub fn channel(self) -> (Sender>, Receiver>) { 169 | (self.sender, self.receiver) 170 | } 171 | } 172 | --------------------------------------------------------------------------------