├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md ├── pull_request_template.md └── workflows │ └── ci.yml ├── .gitignore ├── .travis.yml ├── .umirc.ts ├── CHANGELOG.md ├── Cargo.toml ├── LICENSE ├── README.md ├── TODO.md ├── core ├── Cargo.toml ├── build.rs └── src │ ├── either.rs │ ├── identity.rs │ ├── identity │ ├── ed25519.rs │ ├── error.rs │ ├── rsa.rs │ ├── secp256k1.rs │ └── test │ │ ├── rsa-2048.pk8 │ │ ├── rsa-3072.pk8 │ │ └── rsa-4096.pk8 │ ├── keys.proto │ ├── lib.rs │ ├── metricmap.rs │ ├── multistream │ ├── length_delimited.rs │ ├── mod.rs │ ├── muxer.rs │ ├── negotiator.rs │ ├── protocol.rs │ └── tests.rs │ ├── muxing.rs │ ├── peer_id.rs │ ├── peerstore.rs │ ├── pnet │ ├── crypt_writer.rs │ └── mod.rs │ ├── routing.rs │ ├── secure_io.rs │ ├── translation.rs │ ├── transport.rs │ ├── transport │ ├── dummy.rs │ ├── memory.rs │ ├── protector.rs │ ├── timeout.rs │ └── upgrade.rs │ ├── upgrade.rs │ ├── upgrade │ ├── dummy.rs │ ├── multistream.rs │ └── select.rs │ └── util │ └── mod.rs ├── docs ├── architecture.md ├── intro.md ├── kad.md ├── multistream.md ├── peerstore.md ├── protocol_handler.md ├── readwrite.md ├── security.md ├── stream_muxer.md ├── swarm.md ├── transport_upgrade.md └── uprgader.md ├── examples ├── basichost_concurrent.rs ├── chat │ ├── README.md │ ├── chat.rs │ └── go │ │ ├── chat.go │ │ ├── go.mod │ │ └── go.sum ├── dns_transport.rs ├── ipfs_private_floodsub.rs ├── kad_simple.rs ├── memory_transport.rs ├── protector_network.rs ├── swarm_simple.rs └── websocket │ ├── cert │ ├── ca.cert │ ├── end.cert │ └── end.rsa │ ├── websocket.rs │ └── websocket_tls.rs ├── exporter ├── Cargo.toml ├── README.md └── src │ ├── exporter.rs │ └── lib.rs ├── infoserver ├── Cargo.toml ├── README.md └── src │ └── lib.rs ├── multiaddr ├── Cargo.toml ├── LICENSE ├── src │ ├── errors.rs │ ├── from_url.rs │ ├── lib.rs │ ├── onion_addr.rs │ └── protocol.rs └── tests │ └── lib.rs ├── package-lock.json ├── package.json ├── protocols ├── floodsub │ ├── Cargo.toml │ ├── README.md │ ├── build.rs │ ├── ds_addr_book.txt │ ├── examples │ │ └── floodsub_chat.rs │ ├── src │ │ ├── control.rs │ │ ├── floodsub.rs │ │ ├── lib.rs │ │ ├── protocol.rs │ │ ├── rpc.proto │ │ └── subscription.rs │ └── tests │ │ ├── floodsub_tests.rs │ │ └── smoke.rs ├── gossipsub │ ├── CHANGELOG.md │ ├── Cargo.toml │ ├── build.rs │ ├── src │ │ ├── backoff.rs │ │ ├── cli.rs │ │ ├── compat.proto │ │ ├── config.rs │ │ ├── control.rs │ │ ├── error.rs │ │ ├── gossip_promises.rs │ │ ├── gossipsub.rs │ │ ├── handler.rs │ │ ├── lib.rs │ │ ├── mcache.rs │ │ ├── peer_score.rs │ │ ├── peer_score │ │ │ ├── params.rs │ │ │ └── tests.rs │ │ ├── protocol.rs │ │ ├── rpc.proto │ │ ├── rpc_proto.rs │ │ ├── subscription.rs │ │ ├── subscription_filter.rs │ │ ├── time_cache.rs │ │ ├── topic.rs │ │ ├── transform.rs │ │ └── types.rs │ └── tests │ │ ├── gossip_unit_tests.rs │ │ └── gossipsub_tests.rs ├── kad │ ├── Cargo.toml │ ├── README.md │ ├── build.rs │ ├── examples │ │ ├── bucket.rs │ │ └── task_limiter.rs │ ├── src │ │ ├── addresses.rs │ │ ├── cli.rs │ │ ├── control.rs │ │ ├── dht.proto │ │ ├── kad.rs │ │ ├── kbucket.rs │ │ ├── kbucket │ │ │ ├── bucket.rs │ │ │ ├── entry.rs │ │ │ └── key.rs │ │ ├── lib.rs │ │ ├── protocol.rs │ │ ├── query.rs │ │ ├── record.rs │ │ └── record │ │ │ ├── store.rs │ │ │ └── store │ │ │ └── memory.rs │ └── tests │ │ └── kad_test.rs ├── mdns │ ├── Cargo.toml │ ├── README.md │ ├── examples │ │ └── mdns_simple.rs │ └── src │ │ ├── control.rs │ │ ├── dns.rs │ │ ├── lib.rs │ │ └── service.rs ├── mplex │ ├── Cargo.toml │ ├── examples │ │ ├── mplex_concurrent.rs │ │ └── mplex_simple.rs │ ├── src │ │ ├── connection.rs │ │ ├── connection │ │ │ ├── control.rs │ │ │ └── stream.rs │ │ ├── error.rs │ │ ├── frame.rs │ │ ├── frame │ │ │ ├── header.rs │ │ │ ├── io.rs │ │ │ └── length_delimited.rs │ │ ├── lib.rs │ │ └── pause.rs │ └── tests │ │ └── mplex_tests.rs ├── noise │ ├── Cargo.toml │ ├── build.rs │ ├── src │ │ ├── error.rs │ │ ├── io.rs │ │ ├── io │ │ │ ├── framed.rs │ │ │ ├── handshake.rs │ │ │ └── handshake │ │ │ │ └── payload.proto │ │ ├── lib.rs │ │ ├── protocol.rs │ │ ├── protocol │ │ │ ├── x25519.rs │ │ │ └── x25519_spec.rs │ │ └── upgrade.rs │ └── tests │ │ └── testx.rs ├── plaintext │ ├── Cargo.toml │ ├── build.rs │ ├── examples │ │ └── plaintext_simple.rs │ └── src │ │ ├── error.rs │ │ ├── handshake │ │ ├── handshake_plaintext.rs │ │ ├── mod.rs │ │ └── structs.proto │ │ ├── lib.rs │ │ └── secure_stream.rs ├── secio │ ├── Cargo.toml │ ├── benches │ │ └── bench.rs │ ├── build.rs │ ├── examples │ │ ├── go │ │ │ ├── Dockerfile │ │ │ ├── go.mod │ │ │ ├── go.sum │ │ │ └── server.go │ │ └── secio_simple.rs │ └── src │ │ ├── codec │ │ ├── mod.rs │ │ └── secure_stream.rs │ │ ├── crypto │ │ ├── cipher.rs │ │ ├── ctr_impl.rs │ │ ├── keys.proto │ │ ├── mod.rs │ │ └── ring_impl.rs │ │ ├── error.rs │ │ ├── exchange.rs │ │ ├── handshake │ │ ├── handshake_context.rs │ │ ├── mod.rs │ │ ├── procedure.rs │ │ └── structs.proto │ │ ├── lib.rs │ │ └── support.rs └── yamux │ ├── Cargo.toml │ ├── examples │ └── yamux_simple.rs │ └── src │ └── lib.rs ├── runtime ├── Cargo.toml ├── README.md ├── examples │ └── task_simple.rs └── src │ ├── async_std │ ├── mod.rs │ ├── net.rs │ └── task.rs │ ├── lib.rs │ ├── limit.rs │ └── tokio │ ├── mod.rs │ ├── net.rs │ └── task.rs ├── rust-toolchain ├── rustfmt.toml ├── src └── lib.rs ├── swarm ├── Cargo.toml ├── build.rs └── src │ ├── cli.rs │ ├── connection.rs │ ├── control.rs │ ├── dial.rs │ ├── identify.rs │ ├── identify │ └── structs.proto │ ├── lib.rs │ ├── metrics │ ├── metric.rs │ ├── metricmap.rs │ ├── mod.rs │ └── snapshot.rs │ ├── muxer.rs │ ├── network.rs │ ├── ping.rs │ ├── protocol_handler.rs │ ├── registry.rs │ └── substream.rs └── transports ├── dns ├── Cargo.toml └── src │ └── lib.rs ├── tcp ├── Cargo.toml └── src │ └── lib.rs └── websocket ├── Cargo.toml └── src ├── connection.rs ├── error.rs ├── framed.rs ├── lib.rs └── tls.rs /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Desktop (please complete the following information):** 27 | - OS: [e.g. iOS] 28 | - Browser [e.g. chrome, safari] 29 | - Version [e.g. 22] 30 | 31 | **Smartphone (please complete the following information):** 32 | - Device: [e.g. iPhone6] 33 | - OS: [e.g. iOS8.1] 34 | - Browser [e.g. stock browser, safari] 35 | - Version [e.g. 22] 36 | 37 | **Additional context** 38 | Add any other context about the problem here. 39 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | #### Type of change 6 | 7 | 8 | 9 | - Bug fix 10 | - New feature 11 | - Improvement (improvement to code, performance, etc) 12 | - Test update 13 | - Documentation update 14 | 15 | #### Description 16 | 17 | 18 | 19 | #### Additional details 20 | 21 | 22 | 23 | 24 | #### Related issues 25 | 26 | 27 | 28 | 29 | 40 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: Continuous integration 2 | 3 | on: 4 | pull_request: 5 | push: 6 | branches: 7 | - master 8 | jobs: 9 | fmt_clippy_docs: 10 | name: Checking fmt, clippy, and docs 11 | runs-on: [self-hosted, linux, X64] 12 | steps: 13 | - uses: actions/checkout@v2 14 | 15 | - uses: actions-rs/toolchain@v1 16 | with: 17 | toolchain: 1.57 18 | override: true 19 | 20 | - name: setup 21 | run: | 22 | rustup component add clippy rustfmt 23 | rustc --version 24 | 25 | - name: clippy 26 | run: RUSTFLAGS='-F warnings' cargo clippy --all --examples --tests 27 | 28 | - name: fmt 29 | run: cargo fmt --all -- --check 30 | 31 | - name: docs 32 | run: cargo doc 33 | 34 | build_and_test: 35 | name: Build and test 36 | needs: [fmt_clippy_docs] 37 | runs-on: ${{ matrix.os }} 38 | strategy: 39 | matrix: 40 | os: [[self-hosted, linux, X64]] 41 | rust: [1.57.0] 42 | 43 | steps: 44 | - uses: actions/checkout@v2 45 | 46 | - name: Install ${{ matrix.rust }} 47 | uses: actions-rs/toolchain@v1 48 | with: 49 | toolchain: ${{ matrix.rust }} 50 | override: true 51 | 52 | - name: Build 53 | run: cargo build --release --examples --all 54 | - name: Unit test 55 | run: cargo test --all 56 | - name: Bench test 57 | run: cargo bench --all -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | **/target 3 | **/*.rs.bk 4 | .idea/ 5 | .vscode/ 6 | Cargo.lock 7 | node_modules 8 | dist 9 | .umi -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: rust 2 | env: 3 | - RUSTFLAGS='-F warnings' 4 | rust: 5 | - stable 6 | # - nightly 7 | # - beta 8 | os: 9 | - linux 10 | # - osx 11 | - windows 12 | services: 13 | - docker 14 | before_script: 15 | - rustup component add rustfmt 16 | - rustup component add clippy 17 | script: 18 | - cargo build --verbose --all 19 | stages: 20 | - Check 21 | - Test 22 | cache: cargo 23 | matrix: 24 | allow_failures: 25 | - rust: nightly 26 | fast_finish: true 27 | include: 28 | - stage: Check 29 | name: Format 30 | script: 31 | - cargo fmt --all -- --check 32 | - stage: Check 33 | name: Clippy 34 | script: 35 | - RUSTFLAGS='-F warnings' cargo clippy --all --examples --tests 36 | - stage: Test 37 | name: unit test and bench test 38 | os: linux 39 | script: 40 | - cargo test --all 41 | - cargo bench --all 42 | branches: 43 | only: master 44 | 45 | notifications: 46 | webhooks: 47 | secure: "jl1eUB947zHMyjPIsQlVlmM4aoCIx0dj/pk9wAIl+0v9CEqleUt7mQPcYlm7xLq+mJrXtjsAGqtn518dM3zQUR4tcJnxrrJTtZzcKBsjIUwsTmufmkjqmYSHGlkj37yaDaB5Hnm1HeqLlgkstg3/c7i8TCEtuRJFzLB4ehpnQ9SzHxdKQrxBricrHXveCgAYI7vAWaOBhO3AceM0rkmTB+2yBWQLKAr1KYtpvcA9GB4KFbR8SlTFuWY7bLnIbBecsCOZE2oUR3wPfN+0FlkJeSp9wg41MKPGqJGkDcea2l5g/CPnCp2RgSN7U11QNdK3pP03L10S8ZoQYkPOdKrlX5hFKAyUVHZLY3jlyzLkZkwavM0lah9wC4ljLqvsCzUJqePZMsov4O4SlyxFVoR/J4qskeVAnCKj+k3a6SyvF7dJOVv0BoKY/ULE4U7zAosItInlKNxmMchUBrF8fgPlx7J7J/5HjhVhoCctmKDT5JHgVjAnPtpxo14b8JfXhJSAU7FPP298DuXA9u3L/ajAIlP0gP+RwsRpmnhWttXw9ziF9DP/B/gFoh7ZGECMBYvgHAedVn+iCzQH09hnPruGwVhGOneD1Ui5iXXubjgl/2qS5LRiuO6tcjbk1kz12vdobb/StoTM6AjVHVfYTFLw5Ltk041hRA9GlEk7eiVxznM=" -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 0.4.0 release (2022.2.23) 2 | ### New Optimizations and changes 3 | 4 | - New: 5 | * Gossip: A pub/sub protocol that supports focusing on one or more topics. 6 | - Optimization: 7 | * Metric: 8 | + use snapshot to calculate rate. 9 | * Kad: 10 | + set TaskLimiter parallelism to control iterator query. 11 | + add environment variables. 12 | * Cli: Add command 13 | + swarm ping: ping a specific peer_id. 14 | + dht pm: provide many keys to dht network. 15 | + dht noaddr: search those peers that address is not in peerstore from KBucket. 16 | * Substream 17 | + add timeout to avoid long hang. 18 | - Dependencies updated: 19 | * Secio: 20 | + because of version yanked, replace aes-ctr to aes. 21 | * Noise: 22 | + updated rand and snow. 23 | - Bug fixed: 24 | * MetricMap: 25 | + Fixed swapping problem when insert new item. 26 | 27 | ## 0.3.0 release (2021.4.23) 28 | 29 | ### Changes 30 | 31 | Eventually we don't depend on ReadEx/WriteEx/SplitEx any longer. Actually we figure out it is better to keep the classic AsyncRead/AsyncWrite, for the sake of backward compatibility. On the other hand, we still have ReadEx/WriteEx, which serve as extensions to AsyncRead/AsyncWrite, providing IO Codec support. 32 | 33 | Besides, there are some changes in Kad-DHT protocol implementation. To be more specific, re-provide/publish functionality is removed from Kad. We tend to believe the logics of re-provide/republish belong to the App using Kad, instead of Kad itself. As a result, the data structures of Provider/Record are simplified accordingly, and there are two gc_xxx methods are required in RecordStore trait, to perform GC for Provider and Records respectively, which is done by tracking the timestamp of Provider/Record received from network. Note that GC will be performed only for the provider/record received from network. 34 | 35 | ## 0.2.2 release (2021.3.1) 36 | 37 | ### Changes 38 | 39 | - Swarm: 40 | * Must implement ProtocolImpl trait for all protocols 41 | + ProtocolImpl includes two methods: handler() & start() 42 | * Protocols main loop(if any) are started by Swarm 43 | - Floodsub 44 | * move .await to independent tasks 45 | * API: Arc to avoid cloning messages for multiple subscribers 46 | - Kad API changed 47 | * bootstrap() allow an initial boot node list 48 | * unprovide() to remove provider from local store 49 | - Other minor changes 50 | 51 | ## 0.2.1 release (2021.1.26) 52 | 53 | - libp2prs_runtime added to support both async-std and tokio 1.0 54 | - feature sets refactored 55 | 56 | 57 | ## 0.2.0 release (2021.1.12) 58 | 59 | ### New features and changes 60 | 61 | - Protocols 62 | + **Kad-DHT**: 63 | * beta-value introduced to better handle iterative query termination 64 | * configurable timeout for iterative query 65 | * auto-refresh mechanism to refresh the routing table in a configurable interval 66 | * health check for any nodes/peers in the routing table whose aliveness is deemed to be outdated 67 | * event handling for peer identified and local address changed 68 | * outgoing sub-streams reuse 69 | * statistics for iterative query - success, failure or timeout 70 | * debugging shell commands 71 | + floodsub: experimental 72 | + mDns: experimental 73 | - Swarm 74 | + async post-processing upgrade when accepting new incoming connections** 75 | + dialer support, dialing multiple addresses in parallel 76 | + improved identify protocol 77 | + metric support and many bug fixes 78 | + notification mechanism for protocol handlers 79 | - Tcp transport: interface address change event 80 | - PeerStore improvement 81 | - Prometheus exporter and Info web server 82 | - An interactive debugging shell, integrated with Swarm and Kad 83 | - Copyright notice updated to conform with MIT license 84 | 85 | ## 0.1.0 Initial release (2020.10.26) 86 | 87 | ### Features 88 | 89 | - Transport: Tcp, Dns, Websocket 90 | - Security IO: secio, plaintext, noise 91 | - Stream Muxing: yamux, mplex 92 | - Transport Upgrade: Multistream select, timeout, protector 93 | - Swarm, with Ping & Identify -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Netwarps Ltd. 4 | Copyright 2017 Parity Technologies (UK) Ltd. 5 | Copyright 2023 Web3 Infrastructure Foundation 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy 8 | of this software and associated documentation files (the "Software"), to deal 9 | in the Software without restriction, including without limitation the rights 10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | copies of the Software, and to permit persons to whom the Software is 12 | furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included in all 15 | copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | SOFTWARE. 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Alternative repository for work on libp2p 2 | 3 | 4 | 5 | ![Continuous integration](https://github.com/netwarps/libp2p-rs/workflows/Continuous%20integration/badge.svg?branch=master) 6 | 7 | This repository is an alternative implementation in `Rust` of the [libp2p](https://libp2p.io) spec. Not like `rust-libp2p`, `libp2p-rs` is written with async/await syntax, and driven by async runtime. Even though, many codes are borrowed from `rust-libp2p` and some from `go-libp2p`. We are trying to keep compatible with the two implementations, but it is unfortunately not guaranteed. 8 | 9 | ## Documentations 10 | 11 | How to use the library? 12 | 13 | As mentioned above, the API is completely different from `rust-libp2p`. There is no such thing as 'NetworkBehaviour' in `libp2p-rs` at all. Instead, you should build the Swarm with the transports you like to use, then you have to create a Swarm::Control from it. The Swarm::Control is exposing all Swarm APIs which can be used to manipulate the Swarm - open/read/write/close streams and even more. This is quite similar as the BasicHost in `go-libp2p`. As for Kad-DHT, similarly you should get the Kad::Control for the same reason. Furthermore, you can combine the Swarm with Kad, after that you have the RoutedHost, which has a routing functionality over the BasicHost. 14 | 15 | It is strongly recommended to check the docs and sample code in details: 16 | 17 | - API Documentations can be found: https://docs.rs/libp2p-rs 18 | - Design documentation can be found in `docs` 19 | 20 | Code examples: 21 | 22 | - Details about how to write your code can be found in `examples` 23 | + swarm_simple demonstrates how to build transport and create sub-stream for communication 24 | + kad_simple demonstrates how to run a Kad-DHT server. In this example, the interactive shell is integrated for debugging/observing Kad-DHT internal data structures 25 | + ... 26 | 27 | ## Releases 28 | 29 | NOTE: The master branch is now an active development branch (starting with v0.1.0), which means breaking changes could be made at any time. 30 | -------------------------------------------------------------------------------- /TODO.md: -------------------------------------------------------------------------------- 1 | 2 | As compared with `rust-libp2p`, we have managed to close many gaps in release v0.2.0, since Kad-DHT is introduced and swarm is improved. However, there are still a long to-do list for us. 3 | 4 | ## General 5 | 6 | - **Tokio runtime support** 7 | 8 | ## Core 9 | 10 | - **TCP reuse port**: dialing reuse the port that TCP is listening on 11 | - ~~**Transport Upgrade async-post processing**: post processing accept() and protocol upgrading in parallel~~ 12 | - ~~**Metrics**: bandwidth metric counters and report~~ 13 | - ReadEx/WriteEx/SplitEx removal: unfortunately they are proved to be a failure 14 | 15 | ## Swarm 16 | 17 | - ~~**Swarm dialer**: dialing multiple Multiaddr in parallel~~ 18 | - **Event Bus**: A pub/sub event subscription system: probably not needed any more 19 | - ~~**PeerStore serialization**: serialization/deserialization methods for peer IDs~~ 20 | - ~~Observed address change: handling the observed address changes~~ 21 | - Swarm identify delta protocol, and certificated peer record 22 | - Swarm filters: Multiaddr, PeerId white/black list 23 | 24 | 25 | ## Security Layer 26 | 27 | - ~~**Noise**: Noise implementation~~ 28 | - TLS 29 | 30 | ## Transport 31 | 32 | - Quicc 33 | 34 | ## Routing 35 | 36 | - **Pubsub**: ~~flood~~/random/gossip 37 | - ~~KAD/DHT~~ 38 | - ~~mDNS~~ 39 | 40 | ## Misc. 41 | 42 | - NAT port mapping: uPnP or NAT-PMP 43 | 44 | -------------------------------------------------------------------------------- /core/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "libp2prs-core" 3 | version = "0.4.0" 4 | license = "MIT" 5 | description = "Core traits and structs of libp2p" 6 | authors = ["Netwarps Technologies admin@paradeum.com"] 7 | repository = "https://github.com/netwarps/libp2p-rs" 8 | keywords = ["peer-to-peer", "libp2p", "networking"] 9 | categories = ["network-programming", "asynchronous"] 10 | edition = "2018" 11 | 12 | [dependencies] 13 | asn1_der = "0.6.1" 14 | bs58 = "0.4.0" 15 | ed25519-dalek ={ version="1.0.0-pre.4"} 16 | fnv = "1.0" 17 | futures = { version = "0.3", features = ["std"], default-features = false } 18 | futures-timer = "3" 19 | lazy_static = "1.2" 20 | libsecp256k1 = { version = "0.3.1", optional = true } 21 | log = "0.4" 22 | multihash = { version = "0.13", default-features = false, features = ["std", "multihash-impl", "identity", "sha2"] } 23 | prost = "0.6.1" 24 | rand = "0.7" 25 | sha2 = "0.8.0" 26 | smallvec = "1.0" 27 | thiserror = "1.0" 28 | unsigned-varint = "0.4" 29 | zeroize = "1" 30 | async-trait = "0.1" 31 | parking_lot = "0.10.0" 32 | rw-stream-sink = "0.2.0" 33 | bytes = "0.5" 34 | pin-project = "0.4" 35 | libp2p-pnet = "0.20.0" 36 | crossbeam-epoch = "0.9" 37 | 38 | ring = { version = "0.16.9", features = ["alloc", "std"], default-features = true } 39 | salsa20 = "0.7" 40 | sha3 = "0.8" 41 | serde = { version = "1.0.117", features = ["derive"] } 42 | serde_json = "1.0.59" 43 | 44 | libp2prs-multiaddr = { path = "../multiaddr", version = "0.4.0" } 45 | 46 | [dev-dependencies] 47 | quickcheck = "0.9.0" 48 | libp2prs-runtime = { path = "../runtime", version = "0.4.0", features = ["async-std"] } 49 | multihash = { version = "0.13", default-features = false, features = ["arb"] } 50 | 51 | [build-dependencies] 52 | prost-build = "0.6" 53 | 54 | [features] 55 | default = ["secp256k1"] 56 | secp256k1 = ["libsecp256k1"] 57 | 58 | -------------------------------------------------------------------------------- /core/build.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Parity Technologies (UK) Ltd. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a 4 | // copy of this software and associated documentation files (the "Software"), 5 | // to deal in the Software without restriction, including without limitation 6 | // the rights to use, copy, modify, merge, publish, distribute, sublicense, 7 | // and/or sell copies of the Software, and to permit persons to whom the 8 | // Software is furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 14 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 19 | // DEALINGS IN THE SOFTWARE. 20 | 21 | fn main() { 22 | prost_build::compile_protos(&["src/keys.proto"], &["src"]).unwrap(); 23 | } 24 | -------------------------------------------------------------------------------- /core/src/identity/error.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Parity Technologies (UK) Ltd. 2 | // Copyright 2020 Netwarps Ltd. 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a 5 | // copy of this software and associated documentation files (the "Software"), 6 | // to deal in the Software without restriction, including without limitation 7 | // the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 | // and/or sell copies of the Software, and to permit persons to whom the 9 | // Software is furnished to do so, subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 15 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 20 | // DEALINGS IN THE SOFTWARE. 21 | 22 | //! Errors during identity key operations. 23 | 24 | use std::error::Error; 25 | use std::fmt; 26 | 27 | /// An error during decoding of key material. 28 | #[derive(Debug)] 29 | pub struct DecodingError { 30 | msg: String, 31 | source: Option>, 32 | } 33 | 34 | impl DecodingError { 35 | pub(crate) fn new(msg: S) -> Self { 36 | Self { 37 | msg: msg.to_string(), 38 | source: None, 39 | } 40 | } 41 | 42 | pub(crate) fn source(self, source: impl Error + Send + Sync + 'static) -> Self { 43 | Self { 44 | source: Some(Box::new(source)), 45 | ..self 46 | } 47 | } 48 | } 49 | 50 | impl fmt::Display for DecodingError { 51 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 52 | write!(f, "Key decoding error: {}", self.msg) 53 | } 54 | } 55 | 56 | impl Error for DecodingError { 57 | fn source(&self) -> Option<&(dyn Error + 'static)> { 58 | self.source.as_ref().map(|s| &**s as &dyn Error) 59 | } 60 | } 61 | 62 | /// An error during signing of a message. 63 | #[derive(Debug)] 64 | pub struct SigningError { 65 | msg: String, 66 | source: Option>, 67 | } 68 | 69 | /// An error during encoding of key material. 70 | impl SigningError { 71 | pub(crate) fn new(msg: S) -> Self { 72 | Self { 73 | msg: msg.to_string(), 74 | source: None, 75 | } 76 | } 77 | 78 | pub(crate) fn source(self, source: impl Error + Send + Sync + 'static) -> Self { 79 | Self { 80 | source: Some(Box::new(source)), 81 | ..self 82 | } 83 | } 84 | } 85 | 86 | impl fmt::Display for SigningError { 87 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 88 | write!(f, "Key signing error: {}", self.msg) 89 | } 90 | } 91 | 92 | impl Error for SigningError { 93 | fn source(&self) -> Option<&(dyn Error + 'static)> { 94 | self.source.as_ref().map(|s| &**s as &dyn Error) 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /core/src/identity/test/rsa-2048.pk8: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/web3infra-foundation/libp2p-rs/95263110f15cca1cd42c88a599b05f4eaf00c515/core/src/identity/test/rsa-2048.pk8 -------------------------------------------------------------------------------- /core/src/identity/test/rsa-3072.pk8: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/web3infra-foundation/libp2p-rs/95263110f15cca1cd42c88a599b05f4eaf00c515/core/src/identity/test/rsa-3072.pk8 -------------------------------------------------------------------------------- /core/src/identity/test/rsa-4096.pk8: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/web3infra-foundation/libp2p-rs/95263110f15cca1cd42c88a599b05f4eaf00c515/core/src/identity/test/rsa-4096.pk8 -------------------------------------------------------------------------------- /core/src/keys.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto2"; 2 | 3 | package keys_proto; 4 | 5 | enum KeyType { 6 | RSA = 0; 7 | Ed25519 = 1; 8 | Secp256k1 = 2; 9 | } 10 | 11 | message PublicKey { 12 | required KeyType Type = 1; 13 | required bytes Data = 2; 14 | } 15 | 16 | message PrivateKey { 17 | required KeyType Type = 1; 18 | required bytes Data = 2; 19 | } 20 | -------------------------------------------------------------------------------- /core/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Netwarps Ltd. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a 4 | // copy of this software and associated documentation files (the "Software"), 5 | // to deal in the Software without restriction, including without limitation 6 | // the rights to use, copy, modify, merge, publish, distribute, sublicense, 7 | // and/or sell copies of the Software, and to permit persons to whom the 8 | // Software is furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 14 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 19 | // DEALINGS IN THE SOFTWARE. 20 | 21 | //! Transports, upgrades, multiplexing and node handling of *libp2p*. 22 | //! 23 | //! The main concepts of libp2p-core are: 24 | //! 25 | //! - A [`PeerId`] is a unique global identifier for a node on the network. 26 | //! Each node must have a different `PeerId`. Normally, a `PeerId` is the 27 | //! hash of the public key used to negotiate encryption on the 28 | //! communication channel, thereby guaranteeing that they cannot be spoofed. 29 | //! - The [`Transport`] trait defines how to reach a remote node or listen for 30 | //! incoming remote connections. See the `transport` module. 31 | //! - The [`StreamMuxer`] trait is implemented on structs that hold a connection 32 | //! to a remote and can subdivide this connection into multiple substreams. 33 | //! See the `muxing` module. 34 | //! - The [`UpgradeInfo`] and [`Upgrader`] traits define how to upgrade each 35 | //! individual substream to use a protocol. 36 | //! See the `upgrade` module. 37 | 38 | pub mod keys_proto { 39 | include!(concat!(env!("OUT_DIR"), "/keys_proto.rs")); 40 | } 41 | 42 | // re-export multiaddr 43 | pub use libp2prs_multiaddr as multiaddr; 44 | // re-export multihash 45 | pub use multihash; 46 | 47 | pub mod identity; 48 | mod peer_id; 49 | 50 | pub mod multistream; 51 | 52 | pub use identity::PublicKey; 53 | pub use peer_id::PeerId; 54 | 55 | pub mod transport; 56 | pub use libp2prs_multiaddr::Multiaddr; 57 | pub use transport::Transport; 58 | 59 | pub mod muxing; 60 | pub mod secure_io; 61 | pub mod upgrade; 62 | pub use upgrade::ProtocolId; 63 | pub mod routing; 64 | 65 | pub mod either; 66 | 67 | pub mod peerstore; 68 | 69 | pub mod pnet; 70 | pub mod translation; 71 | 72 | pub mod metricmap; 73 | pub mod util; 74 | 75 | pub use util::{ReadEx, WriteEx}; 76 | -------------------------------------------------------------------------------- /core/src/routing.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Netwarps Ltd. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a 4 | // copy of this software and associated documentation files (the "Software"), 5 | // to deal in the Software without restriction, including without limitation 6 | // the rights to use, copy, modify, merge, publish, distribute, sublicense, 7 | // and/or sell copies of the Software, and to permit persons to whom the 8 | // Software is furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 14 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 19 | // DEALINGS IN THE SOFTWARE. 20 | 21 | //! Routing provides the capability of finding a peer with the given peer Id. 22 | //! 23 | //! The `Routing` traits is implemented on types that provide the find_peer 24 | //! method.. 25 | //! 26 | 27 | use async_trait::async_trait; 28 | 29 | use crate::transport::TransportError; 30 | use crate::{Multiaddr, PeerId}; 31 | 32 | /// `routing` trait for finding a peer. 33 | #[async_trait] 34 | pub trait Routing: Send { 35 | /// Retrieves the addresses of a remote peer. 36 | /// 37 | /// Any types supporting this trait can be used to search network for the 38 | /// addresses, f.g., Kad-DHT. 39 | async fn find_peer(&mut self, peer_id: &PeerId) -> Result, TransportError>; 40 | 41 | /// Retrieves the providers for the given key. 42 | async fn find_providers(&mut self, key: Vec, count: usize) -> Result, TransportError>; 43 | 44 | /// Starts announcing the given key to the content routing network. 45 | async fn provide(&mut self, key: Vec) -> Result<(), TransportError>; 46 | 47 | /// Stops announcing the given key to the content routing network. 48 | async fn cancel_provide(&mut self, key: Vec) -> Result<(), TransportError>; 49 | 50 | /// Lookups the closer peers with given key 51 | async fn lookup(&mut self, key: Vec) -> Result, TransportError>; 52 | 53 | /// Lookups the closer peers in local buckets with given key 54 | async fn bucket_lookup(&mut self, key: Vec) -> Result, TransportError>; 55 | 56 | fn box_clone(&self) -> IRouting; 57 | } 58 | 59 | pub type IRouting = Box; 60 | 61 | impl Clone for IRouting { 62 | fn clone(&self) -> Self { 63 | self.box_clone() 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /core/src/secure_io.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Netwarps Ltd. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a 4 | // copy of this software and associated documentation files (the "Software"), 5 | // to deal in the Software without restriction, including without limitation 6 | // the rights to use, copy, modify, merge, publish, distribute, sublicense, 7 | // and/or sell copies of the Software, and to permit persons to whom the 8 | // Software is furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 14 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 19 | // DEALINGS IN THE SOFTWARE. 20 | 21 | use crate::identity::Keypair; 22 | use crate::{PeerId, PublicKey}; 23 | 24 | /// SecureInfo provides the underlying secure information of a secure connection. 25 | /// 26 | /// The connection upgraded by secure stream, e.g. SecIo, must implement this trait. 27 | pub trait SecureInfo { 28 | fn local_peer(&self) -> PeerId; 29 | 30 | fn remote_peer(&self) -> PeerId; 31 | 32 | fn local_priv_key(&self) -> Keypair; 33 | 34 | fn remote_pub_key(&self) -> PublicKey; 35 | } 36 | -------------------------------------------------------------------------------- /core/src/transport/dummy.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Parity Technologies (UK) Ltd. 2 | // Copyright 2020 Netwarps Ltd. 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a 5 | // copy of this software and associated documentation files (the "Software"), 6 | // to deal in the Software without restriction, including without limitation 7 | // the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 | // and/or sell copies of the Software, and to permit persons to whom the 9 | // Software is furnished to do so, subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 15 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 20 | // DEALINGS IN THE SOFTWARE. 21 | 22 | use crate::transport::{ConnectionInfo, IListener, ITransport, ListenerEvent, Transport, TransportError, TransportListener}; 23 | use crate::Multiaddr; 24 | use async_trait::async_trait; 25 | use std::fmt; 26 | 27 | /// Implementation of `Transport` that doesn't support any multiaddr. 28 | /// 29 | /// Useful for testing purposes, or as a fallback implementation when no protocol is available. 30 | #[derive(Clone)] 31 | pub struct DummyTransport; 32 | 33 | impl DummyTransport { 34 | /// Builds a new `DummyTransport`. 35 | pub fn new() -> Self { 36 | DummyTransport 37 | } 38 | } 39 | 40 | impl Default for DummyTransport { 41 | fn default() -> Self { 42 | DummyTransport::new() 43 | } 44 | } 45 | 46 | impl fmt::Debug for DummyTransport { 47 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 48 | write!(f, "DummyTransport") 49 | } 50 | } 51 | 52 | #[async_trait] 53 | impl Transport for DummyTransport { 54 | type Output = DummyStream; 55 | 56 | fn listen_on(&mut self, _addr: Multiaddr) -> Result, TransportError> { 57 | Err(TransportError::Internal) 58 | } 59 | 60 | async fn dial(&mut self, _addr: Multiaddr) -> Result { 61 | Err(TransportError::Internal) 62 | } 63 | 64 | fn box_clone(&self) -> ITransport { 65 | Box::new(self.clone()) 66 | } 67 | 68 | fn protocols(&self) -> Vec { 69 | vec![0] 70 | } 71 | } 72 | 73 | pub struct DummyListener; 74 | 75 | #[async_trait] 76 | impl TransportListener for DummyListener { 77 | type Output = DummyStream; 78 | 79 | async fn accept(&mut self) -> Result, TransportError> { 80 | Err(TransportError::Internal) 81 | } 82 | 83 | fn multi_addr(&self) -> Option<&Multiaddr> { 84 | None 85 | } 86 | } 87 | 88 | pub struct DummyStream(()); 89 | 90 | impl ConnectionInfo for DummyStream { 91 | fn local_multiaddr(&self) -> Multiaddr { 92 | unimplemented!() 93 | } 94 | 95 | fn remote_multiaddr(&self) -> Multiaddr { 96 | unimplemented!() 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /core/src/upgrade/multistream.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Netwarps Ltd. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a 4 | // copy of this software and associated documentation files (the "Software"), 5 | // to deal in the Software without restriction, including without limitation 6 | // the rights to use, copy, modify, merge, publish, distribute, sublicense, 7 | // and/or sell copies of the Software, and to permit persons to whom the 8 | // Software is furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 14 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 19 | // DEALINGS IN THE SOFTWARE. 20 | 21 | use crate::multistream::Negotiator; 22 | use crate::transport::TransportError; 23 | use crate::upgrade::{ProtocolName, Upgrader}; 24 | use futures::{AsyncRead, AsyncWrite}; 25 | use log::{debug, trace}; 26 | 27 | //b"/multistream/1.0.0" 28 | 29 | /// Multistream that uses multistream-select to select protocols. 30 | /// 31 | /// 32 | #[derive(Debug, Clone)] 33 | pub(crate) struct Multistream { 34 | inner: U, 35 | } 36 | 37 | impl Multistream { 38 | /// Add `Multistream` on top of any `Upgrader`· 39 | /// 40 | /// The protocols supported by the first element have a higher priority. 41 | pub fn new(inner: U) -> Self { 42 | Self { inner } 43 | } 44 | } 45 | 46 | impl Multistream { 47 | pub(crate) async fn select_inbound(self, socket: C) -> Result 48 | where 49 | C: AsyncRead + AsyncWrite + Unpin, 50 | U: Upgrader + Send, 51 | { 52 | trace!("starting multistream select for inbound..."); 53 | let protocols = self.inner.protocol_info(); 54 | let neg = Negotiator::new_with_protocols(protocols.into_iter().map(NameWrap as fn(_) -> NameWrap<_>)); 55 | 56 | let (proto, socket) = neg.negotiate(socket).await?; 57 | 58 | debug!("select_inbound {:?}", proto); 59 | self.inner.upgrade_inbound(socket, proto.0).await 60 | } 61 | 62 | pub(crate) async fn select_outbound(self, socket: C) -> Result 63 | where 64 | C: AsyncRead + AsyncWrite + Unpin, 65 | U: Upgrader + Send, 66 | { 67 | trace!("starting multistream select for outbound..."); 68 | let protocols = self.inner.protocol_info(); 69 | let neg = Negotiator::new_with_protocols(protocols.into_iter().map(NameWrap as fn(_) -> NameWrap<_>)); 70 | 71 | let (proto, socket) = neg.select_one(socket).await?; 72 | 73 | debug!("select_outbound {:?}", proto); 74 | self.inner.upgrade_outbound(socket, proto.0).await 75 | } 76 | } 77 | 78 | #[derive(Clone)] 79 | struct NameWrap(N); 80 | 81 | impl AsRef<[u8]> for NameWrap { 82 | fn as_ref(&self) -> &[u8] { 83 | self.0.protocol_name() 84 | } 85 | } 86 | 87 | impl std::fmt::Debug for NameWrap { 88 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 89 | write!(f, "{}", String::from_utf8_lossy(self.0.protocol_name())) 90 | } 91 | } 92 | 93 | #[cfg(test)] 94 | mod tests { 95 | #[test] 96 | fn to_be_done() {} 97 | } 98 | -------------------------------------------------------------------------------- /docs/intro.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | This repository is an alternative implementation of [libp2p](https://libp2p.io) in `Rust`. The details of what libp2p is can be found at [libp2p-spec](https://github.com/libp2p/specs). 5 | 6 | ## Purpose 7 | 8 | It is one of main purposes to build an alternative implementation that is different from `rust-libp2p`, which we believe is too complicated for developers to comprehend to some extent. As we can see, in `rusts-libp2p` the generic types and associated items seem to be abused a bit, which makes the code very hard to understand. Besides, `rust-libp2p` is using `poll` method to write the code, with all kinds of manual futures and streams. All of these are eventually composed and stacked into a huge state machine, which contains a lot of duplicated/similar code snippets. 9 | 10 | We'd like to make some changes. 11 | 12 | Actually, we've been expierenced `go-libp2p` for a while and we were kind of impressed by the concise implementation. On the other hand, as for Rust, we believe the network I/O async coding can be done in async/await method, in other words, coroutine method, instead of the traiditional `poll` method, given the fact that the async/await syntax was formally released in the second half of 2019. Therefore, as a basic priciple, we are going to write code using `await` as much as possible, to simplify the code by avoid from `poll` and its state machine handling. In addition to that, we'd like to use `trait object` in many places, which is called 'dynamic dispacting' in most time. Not like the generic parameter based 'static dispacting', this could save us from the generic type flooding in a way. 13 | 14 | 15 | ## Objective 16 | 17 | This repository is not intented to replace `rust-libp2p` but to provide a different approach to `libp2p`. As for the first step, `libp2p-rs` will only have the basic functionality, that is to say, `routing` protocols will not be there. 18 | 19 | 20 | ## Design Priciples 21 | 22 | - No unsafe code 23 | - No manual Future or Stream 24 | - Use Trait Object, dynamic dispatching 25 | - Use futures::mpsc::channel, avoid Mutex<> 26 | - Async Trait, to introduce async fn in Trait 27 | - Package async runtime to support either async-std or tokio 28 | 29 | 30 | ## Content 31 | 32 | - [`Architecture`](architecture.md) 33 | - [`ReadEx & WriteEx`](readwrite.md) 34 | - [`Transport Upgrade`](treansport_upgrade.md) 35 | - [`Security Stream`](security.md) 36 | - [`Stream Muxer`](stream_muxer.md) 37 | - [`Multistream Select`](multistream.md) 38 | - [`Upgrader`](upgrader.md) 39 | - [`Swarm`](swarm.md) 40 | - [`Protocol Handler`](protocol_handler.md) 41 | -------------------------------------------------------------------------------- /docs/multistream.md: -------------------------------------------------------------------------------- 1 | 2 | # Multistream select 3 | 4 | Multistream Select is a friendly protocol negotiation. -------------------------------------------------------------------------------- /docs/peerstore.md: -------------------------------------------------------------------------------- 1 | PeerStore provides a way to store peer information. 2 | 3 | In `go-libp2p-peerstore`, it has two difference implementations: pstoreds and pstoremem. Both of them include three 4 | attributes: AddrBook, ProtoBook, KeyBook. 5 | 6 | In `libp2p-rs`, we use a new struct called `PeerRecord` to store all of the attributes. 7 | It may used in concurrency, so outside is designed as a Hashmap that wrapped by `Arc`. 8 | 9 | Now let us introduce the structure of `PeerRecord` simply: 10 | 11 | `pinned`: This is a symbol for garbage collection. In main loop for `Swarm`, a thread started by `task::spawn` is 12 | responsible for an operation that clean up peerstore every 10 minutes. If `pinned` is true, it means gc will never 13 | recycle this PeerRecord. 14 | 15 | `addrs`: A vector saved `AddrBookRecord`. There are three attributes in `AddrBookRecord`: `Multiaddr`, ttl and 16 | the time of initialization(an instant object). When gc is running, if `initial-time.elapsed() > ttl` is true, `AddrBookRecord` 17 | will be deleted. Besides, if `addrs` equals empty, `PeerRecord` will be removed from `Hashmap`. 18 | 19 | `key`: For every `peer_id`, there is an unique `public_key` that correspond with it. `public_key` can use method 20 | `into_peer_id()` to attain `peer_id`, but `peer_id` can't get `public_key` reversely. So we ought to store it. 21 | 22 | `protos`: It is used to record all of the protocol types supported by peer. The reason why we use `HashSet` is that 23 | every record can not be replaced when it already exists inside. While we use `Hashmap`, it may cause memory leak or 24 | incorrectly overwriting if re-insert. -------------------------------------------------------------------------------- /docs/protocol_handler.md: -------------------------------------------------------------------------------- 1 | 2 | # Protocol Handler 3 | 4 | 5 | 6 | A handler for a set of protocols used on a connection with a remote. 7 | 8 | This trait should be implemented for a type that maintains the server side state for the execution of a specific protocol. 9 | 10 | Trait defined as below: 11 | 12 | ```no_run 13 | #[async_trait] 14 | pub trait ProtocolHandler: UpgradeInfo { 15 | /// After we have determined that the remote supports one of the protocols we support, this 16 | /// method is called to start handling the inbound. Swarm will start invoking this method 17 | /// in a newly spawned task. 18 | /// 19 | /// The `info` is the identifier of the protocol, as produced by `protocol_info`. 20 | async fn handle(&mut self, stream: Substream, info: ::Info) -> Result<(), SwarmError>; 21 | /// This is to provide a clone method for the trait object. 22 | fn box_clone(&self) -> IProtocolHandler; 23 | } 24 | 25 | pub type IProtocolHandler = Box + Send + Sync>; 26 | ``` 27 | 28 | > **Note**:: ProtocolHandler is an async trait and can be made into a trait object. 29 | 30 | 31 | ## UpgradeInfo 32 | 33 | The trait ProtocolHandler derives from `UpgradeInfo`, which provides a list of protocols that are supported, e.g. '/foo/1.0.0' and '/foo/2.0.0'. 34 | 35 | 36 | ## Handling a protocol 37 | 38 | Communication with a remote over a set of protocols is initiated in one of two ways: 39 | 40 | - Dialing by initiating a new outbound substream. In order to do so, `Swarm::control::new_stream()` must be invoked with the specified protocols to create a sub-stream. A protocol negotiation procedure will done for the protocols, in which one might be finally selected. Upon success, a `Swarm::Substream` will be returned by `Swarm::control::new_stream()`, and the protocol will be then handled by the owner of the Substream. 41 | 42 | - Listening by accepting a new inbound substream. When a new inbound substream is created on a connection, `Swarm::muxer` is called to negotiate the protocol(s). Upon success, `ProtocolHandler::handle` is called with the final output of the upgrade. 43 | 44 | ## Adding protocol handlers to Swarm 45 | 46 | In general, multiple protocol handlers should be made into trait objects and then added to `Swarm::muxer`. 47 | 48 | ```no_run 49 | /// Creates Swarm with protocol handler. 50 | pub fn with_protocol(mut self, p: IProtocolHandler) -> Self { 51 | self.muxer.add_protocol_handler(p); 52 | self 53 | } 54 | ``` 55 | 56 | 57 | -------------------------------------------------------------------------------- /docs/security.md: -------------------------------------------------------------------------------- 1 | # Security Stream 2 | 3 | Security stream provides the secure session over the underlying I/O connection. Data will be encrypted to transmit in this stream. 4 | Now we have three different security stream implementations: 5 | 6 | ### Secio 7 | Secio generates the public/private key pair based on asymmetric cryptographic algorithm. 8 | In this part we provide RSA, ed25519 and secp256k1. 9 | When both parties use secio to establish a security stream, the following steps will be executed: 10 | 1. Combine a handshake package which contains pubkey, nonce, supported elliptic curve algorithm, symmetric encryption algorithm, hash algorithm. 11 | Then send it to the other party. 12 | 2. Receive the package and confirm algorithms that both intend to use. 13 | 3. Generate a ephemeral public/private key by elliptic curve algorithm. 14 | The ephemeral public key, received and send package are encrypted by private key and send it as the second handshake package to the opposite. 15 | 4. Use opposite's public key to check the received package. 16 | 5. Ensure the symmetric encryption algorithm and hmac, verify the nonce correctly or not. 17 | 6. Finally use encryption and hmac to transmit. 18 | 19 | 20 | ### PlainText 21 | The implementation of plaintext is simple as it doesn't perform the security operations at all. 22 | 23 | Both sides exchange theirs public key, and verify it that matches local key or not. 24 | If result is different, it means that connection has been established. 25 | And then use plaintext to transmit. 26 | 27 | 28 | ### Noise 29 | Noise is more complicated than both secio and plaintext. 30 | Now we only provide `xx` pattern but it has 12 kinds of pattern actually. 31 | The implementation refers to `go-libp2p` and `rust-libp2p`, but we use `async/await` to instead of `poll`. 32 | 33 | Noise use the crate `snow` to implement the real noise protocol. 34 | In this part, we encrypt public key and combine it with private key as a package. 35 | Then send it to `snow`. -------------------------------------------------------------------------------- /docs/stream_muxer.md: -------------------------------------------------------------------------------- 1 | 2 | Muxing is the process of splitting a connection into multiple substreams. 3 | 4 | 5 | ## StreamMuxer Trait 6 | 7 | StreamMuxer Trait is an async trait, used to manipulate substreams over the underlying connection. An implementation of `StreamMuxer` has ownership of a connection, lets you open and close substreams, and read/write data on open substreams. 8 | 9 | Each substream of a connection is an isolated stream of data. All the substreams are muxed together so that the data read from or written to each substream doesn't influence the other substreams. 10 | 11 | In the context of libp2p, each substream can use a different protocol. Contrary to opening a connection, opening a substream is almost free in terms of resources. This means that you 12 | shouldn't hesitate to rapidly open and close substreams, and to design protocols that don't require maintaining long-lived channels of communication. 13 | 14 | ```no_run 15 | #[async_trait] 16 | pub trait StreamMuxer { 17 | /// Opens a new outgoing substream. 18 | async fn open_stream(&mut self) -> Result; 19 | /// Accepts a new incoming substream. 20 | async fn accept_stream(&mut self) -> Result; 21 | /// Closes the stream muxer, the task of stream muxer will then exit. 22 | async fn close(&mut self) -> Result<(), TransportError>; 23 | /// Returns a Future which represents the main loop of the stream muxer. 24 | fn task(&mut self) -> Option>; 25 | /// Returns the cloned Trait object. 26 | fn box_clone(&self) -> IStreamMuxer; 27 | } 28 | 29 | ``` 30 | ## Implementing a muxing protocol 31 | 32 | In order to implement a muxing protocol, create an object that implements the `UpgradeInfo` and `Upgrader` traits. See the `upgrader` module for more information. The `Output` associated type of the `Upgrader` traits should be an object that implements the `StreamMuxer` trait. 33 | 34 | The upgrade process will take ownership of the connection, which makes it possible for the implementation of `StreamMuxer` to control everything that happens on the wire. 35 | 36 | ## Implementations 37 | 38 | There are two StreamMuxer implementations so far. 39 | 40 | ### Yamux 41 | 42 | 43 | ### Mplex 44 | -------------------------------------------------------------------------------- /docs/transport_upgrade.md: -------------------------------------------------------------------------------- 1 | 2 | # Transport Upgrade 3 | 4 | `TransportUpgrade` is a `Transport` that wraps another `Transport` and adds upgrade capabilities to all inbound and outbound connection attempts. As shown below, `TransportUpgrade` consists of two parts: 5 | 6 | - Inner Transport 7 | - TSec: used to upgrade from a regular connection to a secure one 8 | - TMux: used to upgrade from a secure connection to a stream muxer which can be used to open sub-streams 9 | 10 | ```no_run 11 | pub struct TransportUpgrade { 12 | inner: InnerTrans, 13 | mux: Multistream, 14 | sec: Multistream, 15 | } 16 | ``` 17 | 18 | > Note: it implied that TSec and TMux are 'must to have' if constructing a `TransportUpgrade`. Actually they are mandatory and must be in order. 19 | 20 | ### TSec and TMux 21 | 22 | These two generic types represent the upgrading procedures for Security and Stream Muxing respectively. 23 | 24 | TSec is a type implementing `Upgrader`. It takes the inner transport's output and upgrade it to a new connection supporting `SecureInfo`, ReadEx and WriteEx. 25 | 26 | ```no_run 27 | TSec: Upgrader, 28 | TSec::Output: SecureInfo + ReadEx + WriteEx + Unpin, 29 | ``` 30 | 31 | TMux is also an `Upgrader`. It takes the TSec::Output as the input and upgrade it to a stream muxer. 32 | 33 | ```no_run 34 | TMux: Upgrader, 35 | TMux::Output: StreamMuxer, 36 | ``` 37 | 38 | > Both TSec and TMux are wrapped and driven by Multistream for protocol negotiation and selection. 39 | 40 | 41 | ### Known issues 42 | 43 | The `IListener` of Transport Upgrade should handle the incomming connections and the connnection upgrade in a asynchronous post-processing way, so that the upgrade procedure wouldn't block the `IListener` from producing the next incoming connection, hence further connection setup can be proceeded asynchronously. 44 | 45 | Of course it can be done if we start a task to proceed connection upgrade asynchronously, but it requires introducing async runtime into the libp2p core, which we'd like to not to. An alternative approach is to implement a futures::Stream by proceding IListener::accept and connection upgrade in parallel. To be done... -------------------------------------------------------------------------------- /docs/uprgader.md: -------------------------------------------------------------------------------- 1 | # Upgrader 2 | 3 | Upgrader Contains everything related to upgrading a connection to use a protocol. 4 | 5 | After a connection with a remote has been successfully established. The next step is to *upgrade* this connection to use a protocol. 6 | 7 | This is where the `Upgrader` trait comes into play. 8 | The trait is implemented on types that represent a collection of one or more possible protocols for respectively an ingoing or outgoing connection. 9 | 10 | > **Note**: Multiple versions of the same protocol are treated as different protocols. For example, `/foo/1.0.0` and `/foo/1.1.0` are totally unrelated as far as upgrading is concerned. 11 | 12 | 13 | # UpgradeInfo 14 | 15 | The trait Upgrader derives from `UpgradeInfo`, which provides a list of protocols that are supported, e.g. '/foo/1.0.0' and '/foo/2.0.0'. 16 | 17 | > **Note**: `UpgradeInfo` provides the list of protocols, instead of a single protocol. 18 | 19 | # Upgrade process 20 | 21 | An upgrade is performed in two steps: 22 | 23 | - A protocol negotiation step. The `UpgradeInfo::protocol_info` method is called to determine which protocols are supported by the trait implementation. The `multistream-select` protocol is used in order to agree on which protocol to use amongst the ones supported. 24 | 25 | - A handshake. After a successful negotiation, the `Upgrader::upgrade_inbound` or `Upgrader::upgrade_outbound` method is called. This method will return a upgraded 'Connection'. This handshake is considered mandatory, however in practice it is possible for the trait implementation to return a dummy `Connection` that doesn't perform any action and immediately succeeds. 26 | 27 | After an upgrade is successful, an object of type `Upgrader::Output` is returned. The actual object depends on the implementation and there is no constraint on the traits that it should implement, however it is expected that it can be used by the user to control the behaviour of the protocol. 28 | -------------------------------------------------------------------------------- /examples/chat/README.md: -------------------------------------------------------------------------------- 1 | # p2p chat app with libp2p 2 | 3 | 4 | ## Intro 5 | This program demonstrates a simple p2p chat application. It can work between two peers if 6 | 1. Both have a private IP address (same network). 7 | 2. At least one of them has a public IP address. 8 | 9 | Assume if 'A' and 'B' are on different networks host 'A' may or may not have a public IP address but host 'B' has one. 10 | 11 | Node A Viedo 12 | [![asciicast](https://asciinema.org/a/0j1M9VBmuHJ94KdleU2r3Tb1g.svg)](https://asciinema.org/a/0j1M9VBmuHJ94KdleU2r3Tb1g) 13 | 14 | Node B Viedo 15 | [![asciicast](https://asciinema.org/a/cY5VFxZGgmOq6Z021UGAomUrp.svg)](https://asciinema.org/a/cY5VFxZGgmOq6Z021UGAomUrp) 16 | 17 | ## Clone code 18 | ``` 19 | git clone https://github.com/netwarps/libp2p-rs.git 20 | ``` 21 | ## Rust server and Rust client 22 | 23 | ``` 24 | cd libp2p-rs 25 | ``` 26 | 27 | On node 'B'. 28 | ``` 29 | RUST_LOG=info cargo run --example chat server -s 8086 30 | > hi (received messages in green colour) 31 | > hello (sent messages in white colour) 32 | ``` 33 | 34 | On node 'A'. Replace 127.0.0.1 with if node 'B' has one. 35 | ``` 36 | RUST_LOG=info cargo run --example chat client -d /ip4/127.0.0.1/tcp/8086/p2p/12D3KooWDpJ7As7BWAwRMfu1VU2WCqNjvq387JEYKDBj4kx6nXTN 37 | > hi (sent messages in white colour) 38 | > hello (received messages in green colour) 39 | ``` 40 | 41 | 42 | ## Go server and Go client 43 | 44 | 45 | run the following: 46 | 47 | ``` 48 | cd libp2p-rs/examples/chat/go 49 | go build 50 | ``` 51 | 52 | On node 'B'. 53 | 54 | ``` 55 | ./chat -sp 8086 56 | ``` 57 | 58 | On node 'A'. 59 | 60 | ``` 61 | ./chat -d /ip4/127.0.0.1/tcp/8086/p2p/12D3KooWDpJ7As7BWAwRMfu1VU2WCqNjvq387JEYKDBj4kx6nXTN 62 | ``` 63 | 64 | 65 | ## Rust server and Go client 66 | 67 | On node 'B'. 68 | ``` 69 | cd libp2p-rs/ 70 | RUST_LOG=info cargo run --example chat server -s 8086 71 | ``` 72 | 73 | On node 'A'. 74 | ``` 75 | cd examples/chat/go 76 | ./chat -d /ip4/127.0.0.1/tcp/8086/p2p/12D3KooWDpJ7As7BWAwRMfu1VU2WCqNjvq387JEYKDBj4kx6nXTN 77 | ``` 78 | 79 | ## Go server and Rust client 80 | 81 | On node 'B'. 82 | ``` 83 | cd examples/chat/go 84 | ./chat -sp 8086 85 | ``` 86 | 87 | On node 'A'. 88 | ``` 89 | cd libp2p-rs/ 90 | RUST_LOG=info cargo run --example chat client -d /ip4/127.0.0.1/tcp/8086/p2p/12D3KooWDpJ7As7BWAwRMfu1VU2WCqNjvq387JEYKDBj4kx6nXTN 91 | ``` -------------------------------------------------------------------------------- /examples/chat/go/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/libp2p/chat 2 | 3 | require ( 4 | github.com/gogo/protobuf v1.3.1 5 | github.com/google/uuid v1.1.1 6 | github.com/ipfs/go-datastore v0.4.2 7 | github.com/ipfs/go-log v0.0.1 8 | github.com/libp2p/go-libp2p v0.5.2 9 | github.com/libp2p/go-libp2p-autonat-svc v0.1.0 10 | github.com/libp2p/go-libp2p-circuit v0.1.4 11 | github.com/libp2p/go-libp2p-connmgr v0.2.1 12 | github.com/libp2p/go-libp2p-core v0.3.0 13 | github.com/libp2p/go-libp2p-discovery v0.2.0 14 | github.com/libp2p/go-libp2p-kad-dht v0.5.0 15 | github.com/libp2p/go-libp2p-quic-transport v0.2.3 16 | github.com/libp2p/go-libp2p-routing v0.1.0 17 | github.com/libp2p/go-libp2p-secio v0.2.2 18 | github.com/libp2p/go-libp2p-swarm v0.2.2 19 | github.com/libp2p/go-libp2p-testing v0.1.1 20 | github.com/libp2p/go-libp2p-tls v0.1.3 21 | github.com/multiformats/go-multiaddr v0.2.0 22 | github.com/multiformats/go-multiaddr-net v0.1.2 23 | github.com/whyrusleeping/go-logging v0.0.1 24 | ) 25 | 26 | go 1.13 27 | -------------------------------------------------------------------------------- /examples/websocket/cert/end.cert: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIEADCCAmigAwIBAgICAcgwDQYJKoZIhvcNAQELBQAwLDEqMCgGA1UEAwwhcG9u 3 | eXRvd24gUlNBIGxldmVsIDIgaW50ZXJtZWRpYXRlMB4XDTE2MTIxMDE3NDIzM1oX 4 | DTIyMDYwMjE3NDIzM1owGTEXMBUGA1UEAwwOdGVzdHNlcnZlci5jb20wggEiMA0G 5 | CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC1YDz66+7VD4DL1+/sVHMQ+BbDRgmD 6 | OQlX++mfW8D3QNQm/qDBEbu7T7qqdc9GKDar4WIzBN8SBkzM1EjMGwNnZPV/Tfz0 7 | qUAR1L/7Zzf1GaFZvWXgksyUpfwvmprH3Iy/dpkETwtPthpTPNlui3hZnm/5kkjR 8 | RWg9HmID4O04Ld6SK313v2ZgrPZbkKvbqlqhUnYWjL3blKVGbpXIsuZzEU9Ph+gH 9 | tPcEhZpFsM6eLe+2TVscIrycMEOTXqAAmO6zZ9sQWtfllu3CElm904H6+jA/9Leg 10 | al72pMmkYr8wWniqDDuijXuCPlVx5EDFFyxBmW18UeDEQaKV3kNfelaTAgMBAAGj 11 | gb4wgbswDAYDVR0TAQH/BAIwADALBgNVHQ8EBAMCBsAwHQYDVR0OBBYEFIYhJkVy 12 | AAKT6cY/ruH1Eu+NNxteMEIGA1UdIwQ7MDmAFNwuPy4Do//Sm5CZDrocHWTrNr96 13 | oR6kHDAaMRgwFgYDVQQDDA9wb255dG93biBSU0EgQ0GCAXswOwYDVR0RBDQwMoIO 14 | dGVzdHNlcnZlci5jb22CFXNlY29uZC50ZXN0c2VydmVyLmNvbYIJbG9jYWxob3N0 15 | MA0GCSqGSIb3DQEBCwUAA4IBgQCWV76jfQDZKtfmj45fTwZzoe/PxjWPRbAvSEnt 16 | LRHrPhqQfpMLqpun8uu/w86mHiR/AmiAySMu3zivW6wfGzlRWLi/zCyO6r9LGsgH 17 | bNk5CF642cdZFvn1SiSm1oGXQrolIpcyXu88nUpt74RnY4ETCC1dRQKqxsYufe5T 18 | DOmTm3ChinNW4QRG3yvW6DVuyxVAgZvofyKJOsM3GO6oogIM41aBqZ3UTwmIwp6D 19 | oISdiATslFOzYzjnyXNR8DG8OOkv1ehWuyb8x+hQCZAuogQOWYtCSd6k3kKgd0EM 20 | 4CWbt1XDV9ZJwBf2uxZeKuCu/KIy9auNtijAwPsUv9qxuzko018zhl3lWm5p2Sqw 21 | O7fFshU3A6df8hMw7ST6/tgFY7geT88U4iJhfWMwr/CZSRSVMXhTyJgbLIXxKYZj 22 | Ym5v4NAIQP6hI4HixzQaYgrhW6YX6myk+emMjQLRJHT8uHvmT7fuxMJVWWgsCkr1 23 | C75pRQEagykN/Uzr5e6Tm8sVu88= 24 | -----END CERTIFICATE----- -------------------------------------------------------------------------------- /examples/websocket/cert/end.rsa: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIEogIBAAKCAQEAtWA8+uvu1Q+Ay9fv7FRzEPgWw0YJgzkJV/vpn1vA90DUJv6g 3 | wRG7u0+6qnXPRig2q+FiMwTfEgZMzNRIzBsDZ2T1f0389KlAEdS/+2c39RmhWb1l 4 | 4JLMlKX8L5qax9yMv3aZBE8LT7YaUzzZbot4WZ5v+ZJI0UVoPR5iA+DtOC3ekit9 5 | d79mYKz2W5Cr26paoVJ2Foy925SlRm6VyLLmcxFPT4foB7T3BIWaRbDOni3vtk1b 6 | HCK8nDBDk16gAJjus2fbEFrX5ZbtwhJZvdOB+vowP/S3oGpe9qTJpGK/MFp4qgw7 7 | oo17gj5VceRAxRcsQZltfFHgxEGild5DX3pWkwIDAQABAoIBAFDTazlSbGML/pRY 8 | TTWeyIw2UkaA7npIr45C13BJfitw+1nJPK/tDCDDveZ6i3yzLPHZhV5A/HtWzWC1 9 | 9R7nptOrnO83PNN2nPOVQFxzOe+ClXGdQkoagQp5EXHRTspj0WD9I+FUrDDAcOjJ 10 | BAgMJPyi6zlnZAXGDVa3NGyQDoZqwU2k36L4rEsJIkG0NVurZhpiCexNkkf32495 11 | TOINQ0iKdfJ4iZoEYQ9G+x4NiuAJRCHuIcH76SNfT+Uv3wX0ut5EFPtflnvtdgcp 12 | QVcoKwYdO0+mgO5xqWlBcsujSvgBdiNAGnAxKHWiEaacuIJi4+yYovyEebP6QI2X 13 | Zg/U2wkCgYEA794dE5CPXLOmv6nioVC/ubOESk7vjSlEka/XFbKr4EY794YEqrB1 14 | 8TUqg09Bn3396AS1e6P2shr3bxos5ybhOxDGSLnJ+aC0tRFjd1BPKnA80vZM7ggt 15 | 5cjmdD5Zp0tIQTIAAYU5bONQOwj0ej4PE7lny26eLa5vfvCwlrD+rM0CgYEAwZMN 16 | W/5PA2A+EM08IaHic8my0dCunrNLF890ouZnDG99SbgMGvvEsGIcCP1sai702hNh 17 | VgGDxCz6/HUy+4O4YNFVtjY7uGEpfIEcEI7CsLQRP2ggWEFxThZtnEtO8PbM3J/i 18 | qcS6njHdE+0XuCjgZwGgva5xH2pkWFzw/AIpEN8CgYB2HOo2axWc8T2n3TCifI+c 19 | EqCOsqXU3cBM+MgxgASQcCUxMkX0AuZguuxPMmS+85xmdoMi+c8NTqgOhlYcEJIR 20 | sqXgw9OH3zF8g6513w7Md+4Ld4rUHyTypGWOUfF1pmVS7RsBpKdtTdWA7FzuIMbt 21 | 0HsiujqbheyTFlPuMAOH9QKBgBWS1gJSrWuq5j/pH7J/4EUXTZ6kq1F0mgHlVRJy 22 | qzlvk38LzA2V0a32wTkfRV3wLcnALzDuqkjK2o4YYb42R+5CZlMQaEd8TKtbmE0g 23 | HAKljuaKLFCpun8BcOXiXsHsP5i3GQPisQnAdOsrmWEk7R2NyORa9LCToutWMGVl 24 | uD3xAoGAA183Vldm+m4KPsKS17t8MbwBryDXvowGzruh/Z+PGA0spr+ke4XxwT1y 25 | kMMP1+5flzmjlAf4+W8LehKuVqvQoMlPn5UVHmSxQ7cGx/O/o6Gbn8Q25/6UT+sM 26 | B1Y0rlLoKG62pnkeXp1O4I57gnClatWRg5qw11a8V8e3jvDKIYM= 27 | -----END RSA PRIVATE KEY----- -------------------------------------------------------------------------------- /exporter/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "libp2prs-exporter" 3 | version = "0.4.0" 4 | license = "MIT" 5 | description = "The libp2p exporter" 6 | authors = ["Netwarps Technologies admin@paradeum.com"] 7 | repository = "https://github.com/netwarps/libp2p-rs" 8 | keywords = ["peer-to-peer", "libp2p", "networking"] 9 | categories = ["network-programming", "asynchronous"] 10 | edition = "2018" 11 | 12 | [dependencies] 13 | log = "0.4" 14 | futures = { version = "0.3", features = ["std"], default-features = false } 15 | tide = "0.15.0" 16 | serde = { version = "1.0.117", features = ["derive"] } 17 | serde_json = "1.0.59" 18 | lazy_static = "1.4.0" 19 | prometheus = "0.10.0" 20 | libp2prs-runtime = { path = "../runtime", version = "0.4.0", features = ["async-std"] } 21 | libp2prs-swarm = { path = "../swarm", version = "0.4.0" } 22 | libp2prs-core = { path = "../core", version = "0.4.0" } 23 | 24 | [dev-dependencies] 25 | quickcheck = "0.9.0" 26 | rand = "0.7" 27 | env_logger = "0.8" 28 | -------------------------------------------------------------------------------- /exporter/README.md: -------------------------------------------------------------------------------- 1 | # libp2prs-infoserver 2 | 3 | > A visual interface about metric. 4 | 5 | This is a web api-server that observe swarm's metric. 6 | 7 | ## Usage 8 | ``` 9 | let keypair = Keypair::generate_ed25519_fixed(); 10 | let swarm = Swarm::new(keypair.public()); 11 | let control = swarm.control(); 12 | 13 | let monitor = InfoServer::new(control); 14 | monitor.start("127.0.0.1:8999".to_string()); 15 | ``` -------------------------------------------------------------------------------- /exporter/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Netwarps Ltd. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a 4 | // copy of this software and associated documentation files (the "Software"), 5 | // to deal in the Software without restriction, including without limitation 6 | // the rights to use, copy, modify, merge, publish, distribute, sublicense, 7 | // and/or sell copies of the Software, and to permit persons to whom the 8 | // Software is furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 14 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 19 | // DEALINGS IN THE SOFTWARE. 20 | 21 | pub(crate) mod exporter; 22 | 23 | use prometheus::{register, Encoder, TextEncoder}; 24 | use tide::{Body, Request, Response, Server}; 25 | 26 | use crate::exporter::Exporter; 27 | use libp2prs_runtime::task; 28 | use libp2prs_swarm::Control; 29 | 30 | /// Exporter server 31 | pub struct ExporterServer { 32 | s: Server<()>, 33 | } 34 | 35 | impl ExporterServer { 36 | pub fn new(control: Control) -> Self { 37 | let mut s = tide::new(); 38 | 39 | // Register exporter to global registry, and then we can use default gather method. 40 | let exporter = Exporter::new(control); 41 | let _ = register(Box::new(exporter)); 42 | s.at("/metrics").get(get_metric); 43 | ExporterServer { s } 44 | } 45 | 46 | pub fn start(self, addr: String) { 47 | task::spawn(async move { 48 | let r = self.s.listen(addr).await; 49 | log::info!("Exporter server started result={:?}", r); 50 | }); 51 | } 52 | } 53 | 54 | /// Return metrics to prometheus 55 | async fn get_metric(_: Request<()>) -> tide::Result { 56 | let encoder = TextEncoder::new(); 57 | let metric_families = prometheus::gather(); 58 | let mut buffer = vec![]; 59 | 60 | encoder.encode(&metric_families, &mut buffer).unwrap(); 61 | 62 | let response = Response::builder(200) 63 | .content_type("text/plain; version=0.0.4") 64 | .body(Body::from(buffer)) 65 | .build(); 66 | 67 | Ok(response) 68 | } 69 | -------------------------------------------------------------------------------- /infoserver/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "libp2prs-infoserver" 3 | version = "0.4.0" 4 | license = "MIT" 5 | description = "The libp2p info server" 6 | authors = ["Netwarps Technologies admin@paradeum.com"] 7 | repository = "https://github.com/netwarps/libp2p-rs" 8 | keywords = ["peer-to-peer", "libp2p", "networking"] 9 | categories = ["network-programming", "asynchronous"] 10 | edition = "2018" 11 | 12 | [dependencies] 13 | log = "0.4" 14 | tide = "0.15.0" 15 | serde = { version = "1.0.117", features = ["derive"] } 16 | serde_json = "1.0.59" 17 | lazy_static = "1.4.0" 18 | libp2prs-runtime = { path = "../runtime", version = "0.4.0", features = ["async-std"] } 19 | libp2prs-swarm = { path = "../swarm", version = "0.4.0" } 20 | libp2prs-core = { path = "../core", version = "0.4.0" } 21 | 22 | [dev-dependencies] 23 | quickcheck = "0.9.0" 24 | rand = "0.7" 25 | env_logger = "0.8.1" 26 | -------------------------------------------------------------------------------- /infoserver/README.md: -------------------------------------------------------------------------------- 1 | # libp2prs-infoserver 2 | 3 | > A visual interface about metric. 4 | 5 | This is a web api-server that observe swarm's metric. 6 | 7 | ## Usage 8 | ``` 9 | let keypair = Keypair::generate_ed25519_fixed(); 10 | let swarm = Swarm::new(keypair.public()); 11 | let control = swarm.control(); 12 | 13 | let monitor = InfoServer::new(control); 14 | monitor.start("127.0.0.1:8999".to_string()); 15 | ``` -------------------------------------------------------------------------------- /multiaddr/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "libp2prs-multiaddr" 3 | version = "0.4.0" 4 | license = "MIT" 5 | description = "Implementation of the multiaddr format" 6 | authors = ["Netwarps Technologies admin@paradeum.com"] 7 | repository = "https://github.com/netwarps/libp2p-rs" 8 | keywords = ["peer-to-peer", "libp2p", "networking"] 9 | categories = ["network-programming", "asynchronous"] 10 | edition = "2018" 11 | 12 | [dependencies] 13 | arrayref = "0.3" 14 | bs58 = "0.4.0" 15 | byteorder = "1.3.1" 16 | data-encoding = "2.1" 17 | multihash = { version = "0.13.2", default-features = false, features = ["std", "multihash-impl", "identity", "sha2"] } 18 | percent-encoding = "2.1.0" 19 | serde = "1.0.70" 20 | static_assertions = "1.1" 21 | unsigned-varint = "0.5" 22 | 23 | [dev-dependencies] 24 | bincode = "1" 25 | quickcheck = "0.9.0" 26 | rand = "0.7" 27 | serde_json = "1.0" 28 | -------------------------------------------------------------------------------- /multiaddr/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License 2 | 3 | Copyright (C) 2015-2016 Friedel Ziegelmayer 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 9 | of the Software, and to permit persons to whom the Software is furnished to do 10 | so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | Status API Training Shop Blog About Pricing 22 | -------------------------------------------------------------------------------- /multiaddr/src/errors.rs: -------------------------------------------------------------------------------- 1 | use std::{error, fmt, io, net, num, str, string}; 2 | use unsigned_varint::decode; 3 | 4 | pub type Result = ::std::result::Result; 5 | 6 | /// Error types 7 | #[derive(Debug)] 8 | #[non_exhaustive] 9 | pub enum Error { 10 | DataLessThanLen, 11 | InvalidMultiaddr, 12 | InvalidProtocolString, 13 | InvalidUvar(decode::Error), 14 | ParsingError(Box), 15 | UnknownProtocolId(u32), 16 | UnknownProtocolString(String), 17 | } 18 | 19 | impl fmt::Display for Error { 20 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 21 | match self { 22 | Error::DataLessThanLen => f.write_str("we have less data than indicated by length"), 23 | Error::InvalidMultiaddr => f.write_str("invalid multiaddr"), 24 | Error::InvalidProtocolString => f.write_str("invalid protocol string"), 25 | Error::InvalidUvar(e) => write!(f, "failed to decode unsigned varint: {}", e), 26 | Error::ParsingError(e) => write!(f, "failed to parse: {}", e), 27 | Error::UnknownProtocolId(id) => write!(f, "unknown protocol id: {}", id), 28 | Error::UnknownProtocolString(string) => write!(f, "unknown protocol string: {}", string), //Error::__Nonexhaustive => f.write_str("__Nonexhaustive"), 29 | } 30 | } 31 | } 32 | 33 | impl error::Error for Error { 34 | #[inline] 35 | fn cause(&self) -> Option<&dyn error::Error> { 36 | if let Error::ParsingError(e) = self { 37 | Some(&**e) 38 | } else { 39 | None 40 | } 41 | } 42 | } 43 | 44 | impl From for Error { 45 | fn from(err: io::Error) -> Error { 46 | Error::ParsingError(err.into()) 47 | } 48 | } 49 | 50 | impl From for Error { 51 | fn from(err: multihash::Error) -> Error { 52 | Error::ParsingError(err.into()) 53 | } 54 | } 55 | 56 | impl From for Error { 57 | fn from(err: bs58::decode::Error) -> Error { 58 | Error::ParsingError(err.into()) 59 | } 60 | } 61 | 62 | impl From for Error { 63 | fn from(err: net::AddrParseError) -> Error { 64 | Error::ParsingError(err.into()) 65 | } 66 | } 67 | 68 | impl From for Error { 69 | fn from(err: num::ParseIntError) -> Error { 70 | Error::ParsingError(err.into()) 71 | } 72 | } 73 | 74 | impl From for Error { 75 | fn from(err: string::FromUtf8Error) -> Error { 76 | Error::ParsingError(err.into()) 77 | } 78 | } 79 | 80 | impl From for Error { 81 | fn from(err: str::Utf8Error) -> Error { 82 | Error::ParsingError(err.into()) 83 | } 84 | } 85 | 86 | impl From for Error { 87 | fn from(e: decode::Error) -> Error { 88 | Error::InvalidUvar(e) 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /multiaddr/src/onion_addr.rs: -------------------------------------------------------------------------------- 1 | use std::borrow::Cow; 2 | use std::fmt; 3 | use std::fmt::Debug; 4 | 5 | /// Represents an Onion v3 address 6 | #[derive(Clone)] 7 | pub struct Onion3Addr<'a>(Cow<'a, [u8; 35]>, u16); 8 | 9 | impl<'a> Onion3Addr<'a> { 10 | /// Return the hash of the public key as bytes 11 | pub fn hash(&self) -> &[u8; 35] { 12 | self.0.as_ref() 13 | } 14 | 15 | /// Return the port 16 | pub fn port(&self) -> u16 { 17 | self.1 18 | } 19 | 20 | /// Consume this instance and create an owned version containing the same address 21 | pub fn acquire<'b>(self) -> Onion3Addr<'b> { 22 | Onion3Addr(Cow::Owned(self.0.into_owned()), self.1) 23 | } 24 | } 25 | 26 | impl PartialEq for Onion3Addr<'_> { 27 | fn eq(&self, other: &Self) -> bool { 28 | self.1 == other.1 && self.0[..] == other.0[..] 29 | } 30 | } 31 | 32 | impl Eq for Onion3Addr<'_> {} 33 | 34 | impl From<([u8; 35], u16)> for Onion3Addr<'_> { 35 | fn from(parts: ([u8; 35], u16)) -> Self { 36 | Self(Cow::Owned(parts.0), parts.1) 37 | } 38 | } 39 | 40 | impl<'a> From<(&'a [u8; 35], u16)> for Onion3Addr<'a> { 41 | fn from(parts: (&'a [u8; 35], u16)) -> Self { 42 | Self(Cow::Borrowed(parts.0), parts.1) 43 | } 44 | } 45 | 46 | impl Debug for Onion3Addr<'_> { 47 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { 48 | f.debug_tuple("Onion3Addr") 49 | .field(&format!("{:02x?}", &self.0[..])) 50 | .field(&self.1) 51 | .finish() 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "libp2p-rs", 3 | "version": "1.0.0", 4 | "description": "Minimal implementation for a multiplexed p2p network framework", 5 | "scripts": { 6 | "dev": "dumi dev", 7 | "build": "dumi build" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "git+https://github.com/netwarps/libp2p-rs" 12 | }, 13 | "author": "chenguzhen87 <546369005@qq.com>", 14 | "license": "MIT", 15 | "devDependencies": { 16 | "dumi": "^1.1.18" 17 | } 18 | } -------------------------------------------------------------------------------- /protocols/floodsub/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "libp2prs-floodsub" 3 | version = "0.4.0" 4 | license = "MIT" 5 | description = "Floodsub protocol for libp2p" 6 | authors = ["Netwarps Technologies admin@paradeum.com"] 7 | repository = "https://github.com/netwarps/libp2p-rs" 8 | keywords = ["peer-to-peer", "libp2p", "pubsub"] 9 | categories = ["network-programming", "asynchronous"] 10 | edition = "2018" 11 | 12 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 13 | 14 | [features] 15 | async-std = ["libp2prs-swarm/async-std", "libp2prs-runtime/async-std"] 16 | tokio = ["libp2prs-swarm/tokio", "libp2prs-runtime/tokio"] 17 | 18 | [dependencies] 19 | async-trait = "0.1" 20 | futures = { version = "0.3", features = ["std"], default-features = false } 21 | libp2prs-runtime = { path = "../../runtime", version = "0.4.0" } 22 | libp2prs-core = { path = "../../core", version = "0.4.0" } 23 | libp2prs-swarm = { path = "../../swarm", version = "0.4.0" } 24 | log = "0.4" 25 | prost = "0.6" 26 | rand = "0.7" 27 | smallvec = "1.0" 28 | nohash-hasher = "0.2" 29 | 30 | [dev-dependencies] 31 | env_logger = "0.8" 32 | libp2prs-mplex = { path = "../mplex", version = "0.4.0" } 33 | libp2prs-yamux = { path = "../yamux", version = "0.4.0" } 34 | libp2prs-secio = { path = "../secio", version = "0.4.0" } 35 | libp2prs-tcp = { path = "../../transports/tcp", version = "0.4.0", features = ["async-std"] } 36 | lazy_static = "1.4" 37 | quickcheck = "0.9" 38 | 39 | [build-dependencies] 40 | prost-build = "0.6.1" -------------------------------------------------------------------------------- /protocols/floodsub/README.md: -------------------------------------------------------------------------------- 1 | # libp2prs-floodsub 2 | 3 | > the baseline flooding protocol 4 | 5 | This is the canonical pubsub implementation for [libp2p-rs](https://github.com/netwarps/libp2p-rs). 6 | 7 | ## Usage 8 | #### step1: create floodsub and get handler 9 | ```cpp 10 | let floodsub = FloodSub::new(FloodsubConfig::new(local_peer_id)); 11 | let handler = floodsub.handler(); 12 | ``` 13 | #### step2: register handler to swarm 14 | ```cpp 15 | let swarm = Swarm::new(keys.public()) 16 | .with_transport(Box::new(tu)) 17 | .with_protocol(Box::new(handler)) 18 | .with_ping(PingConfig::new().with_unsolicited(true).with_interval(Duration::from_secs(1))) 19 | .with_identify(IdentifyConfig::new(false)); 20 | ``` 21 | #### step3: get floodsub control and then start with swarm control 22 | ```cpp 23 | let floodsub_control = floodsub.control(); 24 | floodsub.start(swarm.control()); 25 | ``` 26 | #### step4: start swarm 27 | ```cpp 28 | // listen on 29 | swarm.listen_on(vec![listen_addr]).unwrap(); 30 | // start swarm 31 | swarm.start(); 32 | // new connection 33 | swarm_control.new_connection(remote_peer_id).await.unwrap(); 34 | ``` 35 | #### step5: publish/subscribe/ls/getPeers 36 | **subscribe** 37 | ```cpp 38 | task::spawn(async move { 39 | let sub = control.subscribe(b"test").await; 40 | if let Some(mut sub) = sub { 41 | loop { 42 | if let Some(msg) = sub.ch.next().await { log::info!("recived: {:?}", msg.data) } 43 | } 44 | } 45 | }); 46 | ``` 47 | **publish** 48 | ```cpp 49 | floodsub_control.publish(Topic::new(b"test"), msg).await; 50 | ``` 51 | **ls** 52 | ```cpp 53 | floodsub_control.ls().await; 54 | ``` 55 | **getPeers** 56 | ```cpp 57 | floodsub_control.get_peers(Topic::new(b"test")); 58 | ``` 59 | ### TODO list: 60 | - config item: sign strict 61 | - filter repetitive message to prevent over flood 62 | - blacklist -------------------------------------------------------------------------------- /protocols/floodsub/build.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Parity Technologies (UK) Ltd. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a 4 | // copy of this software and associated documentation files (the "Software"), 5 | // to deal in the Software without restriction, including without limitation 6 | // the rights to use, copy, modify, merge, publish, distribute, sublicense, 7 | // and/or sell copies of the Software, and to permit persons to whom the 8 | // Software is furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 14 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 19 | // DEALINGS IN THE SOFTWARE. 20 | 21 | fn main() { 22 | prost_build::compile_protos(&["src/rpc.proto"], &["src"]).unwrap(); 23 | } 24 | -------------------------------------------------------------------------------- /protocols/floodsub/ds_addr_book.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/web3infra-foundation/libp2p-rs/95263110f15cca1cd42c88a599b05f4eaf00c515/protocols/floodsub/ds_addr_book.txt -------------------------------------------------------------------------------- /protocols/floodsub/src/control.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Netwarps Ltd. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a 4 | // copy of this software and associated documentation files (the "Software"), 5 | // to deal in the Software without restriction, including without limitation 6 | // the rights to use, copy, modify, merge, publish, distribute, sublicense, 7 | // and/or sell copies of the Software, and to permit persons to whom the 8 | // Software is furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 14 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 19 | // DEALINGS IN THE SOFTWARE. 20 | 21 | use crate::protocol::FloodsubMessage; 22 | use crate::subscription::Subscription; 23 | use crate::Topic; 24 | use crate::{FloodsubConfig, FloodsubError}; 25 | use futures::channel::{mpsc, oneshot}; 26 | use futures::SinkExt; 27 | use libp2prs_core::PeerId; 28 | 29 | pub(crate) enum ControlCommand { 30 | Publish(FloodsubMessage, oneshot::Sender<()>), 31 | Subscribe(Topic, oneshot::Sender), 32 | Ls(oneshot::Sender>), 33 | GetPeers(Topic, oneshot::Sender>), 34 | } 35 | 36 | #[derive(Clone)] 37 | pub struct Control { 38 | config: FloodsubConfig, 39 | control_sender: mpsc::UnboundedSender, 40 | } 41 | 42 | type Result = std::result::Result; 43 | 44 | impl Control { 45 | pub(crate) fn new(control_sender: mpsc::UnboundedSender, config: FloodsubConfig) -> Self { 46 | Control { config, control_sender } 47 | } 48 | /// Closes the floodsub main loop. 49 | pub fn close(&mut self) { 50 | self.control_sender.close_channel(); 51 | } 52 | 53 | /// Publish publishes data to a given topic. 54 | pub async fn publish(&mut self, topic: Topic, data: impl Into>) -> Result<()> { 55 | let msg = FloodsubMessage { 56 | source: self.config.local_peer_id, 57 | data: data.into(), 58 | // If the sequence numbers are predictable, then an attacker could flood the network 59 | // with packets with the predetermined sequence numbers and absorb our legitimate 60 | // messages. We therefore use a random number. 61 | sequence_number: rand::random::<[u8; 20]>().to_vec(), 62 | topics: vec![topic.clone()], 63 | }; 64 | 65 | let (tx, rx) = oneshot::channel(); 66 | self.control_sender.send(ControlCommand::Publish(msg, tx)).await?; 67 | 68 | Ok(rx.await?) 69 | } 70 | 71 | /// Subscribe to messages on a given topic. 72 | pub async fn subscribe(&mut self, topic: Topic) -> Result { 73 | let (tx, rx) = oneshot::channel(); 74 | self.control_sender.send(ControlCommand::Subscribe(topic, tx)).await?; 75 | Ok(rx.await?) 76 | } 77 | 78 | /// List subscribed topics by name. 79 | pub async fn ls(&mut self) -> Result> { 80 | let (tx, rx) = oneshot::channel(); 81 | self.control_sender.send(ControlCommand::Ls(tx)).await?; 82 | Ok(rx.await?) 83 | } 84 | 85 | /// List peers we are currently pubsubbing with. 86 | pub async fn get_peers(&mut self, topic: Topic) -> Result> { 87 | let (tx, rx) = oneshot::channel(); 88 | self.control_sender.send(ControlCommand::GetPeers(topic, tx)).await?; 89 | Ok(rx.await?) 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /protocols/floodsub/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Parity Technologies (UK) Ltd. 2 | // Copyright 2020 Netwarps Ltd. 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a 5 | // copy of this software and associated documentation files (the "Software"), 6 | // to deal in the Software without restriction, including without limitation 7 | // the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 | // and/or sell copies of the Software, and to permit persons to whom the 9 | // Software is furnished to do so, subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 15 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 20 | // DEALINGS IN THE SOFTWARE. 21 | 22 | pub mod control; 23 | pub mod floodsub; 24 | pub mod protocol; 25 | pub mod subscription; 26 | 27 | use futures::channel::{mpsc, oneshot}; 28 | use libp2prs_core::PeerId; 29 | use std::{ 30 | error, 31 | fmt::{Display, Result}, 32 | io, 33 | }; 34 | 35 | mod rpc_proto { 36 | include!(concat!(env!("OUT_DIR"), "/floodsub.pb.rs")); 37 | } 38 | 39 | const FLOOD_SUB_ID: &[u8] = b"/floodsub/1.0.0"; 40 | 41 | /// Configuration options for the Floodsub protocol. 42 | #[derive(Clone)] 43 | pub struct FloodsubConfig { 44 | /// Peer id of the local node. Used for the source of the messages that we publish. 45 | pub local_peer_id: PeerId, 46 | 47 | /// `true` if messages published by local node should be propagated as messages received from 48 | /// the network, `false` by default. 49 | pub subscribe_local_messages: bool, 50 | } 51 | 52 | impl FloodsubConfig { 53 | pub fn new(local_peer_id: PeerId) -> Self { 54 | Self { 55 | local_peer_id, 56 | subscribe_local_messages: false, 57 | } 58 | } 59 | } 60 | 61 | /// Built topic. 62 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] 63 | pub struct Topic(String); 64 | 65 | impl Topic { 66 | /// Returns the id of the topic. 67 | #[inline] 68 | pub fn id(&self) -> &str { 69 | &self.0 70 | } 71 | 72 | pub fn is_empty(&self) -> bool { 73 | self.0.is_empty() 74 | } 75 | 76 | pub fn new(name: S) -> Topic 77 | where 78 | S: Into, 79 | { 80 | Topic(name.into()) 81 | } 82 | } 83 | 84 | impl From for String { 85 | fn from(topic: Topic) -> String { 86 | topic.0 87 | } 88 | } 89 | 90 | #[derive(Debug)] 91 | pub enum FloodsubError { 92 | Io(io::Error), 93 | Closed, 94 | } 95 | 96 | impl error::Error for FloodsubError { 97 | fn source(&self) -> Option<&(dyn error::Error + 'static)> { 98 | match self { 99 | FloodsubError::Io(err) => Some(err), 100 | FloodsubError::Closed => None, 101 | } 102 | } 103 | } 104 | 105 | impl Display for FloodsubError { 106 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result { 107 | match self { 108 | FloodsubError::Io(e) => write!(f, "i/o error: {}", e), 109 | FloodsubError::Closed => f.write_str("floodsub protocol is closed"), 110 | } 111 | } 112 | } 113 | 114 | impl From for FloodsubError { 115 | fn from(e: io::Error) -> Self { 116 | FloodsubError::Io(e) 117 | } 118 | } 119 | 120 | impl From for FloodsubError { 121 | fn from(_: mpsc::SendError) -> Self { 122 | FloodsubError::Closed 123 | } 124 | } 125 | 126 | impl From for FloodsubError { 127 | fn from(_: oneshot::Canceled) -> Self { 128 | FloodsubError::Closed 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /protocols/floodsub/src/rpc.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto2"; 2 | 3 | package floodsub.pb; 4 | 5 | message RPC { 6 | repeated SubOpts subscriptions = 1; 7 | repeated Message publish = 2; 8 | 9 | message SubOpts { 10 | optional bool subscribe = 1; // subscribe or unsubcribe 11 | optional string topic_id = 2; 12 | } 13 | } 14 | 15 | message Message { 16 | optional bytes from = 1; 17 | optional bytes data = 2; 18 | optional bytes seqno = 3; 19 | repeated string topic_ids = 4; 20 | } 21 | -------------------------------------------------------------------------------- /protocols/floodsub/src/subscription.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Netwarps Ltd. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a 4 | // copy of this software and associated documentation files (the "Software"), 5 | // to deal in the Software without restriction, including without limitation 6 | // the rights to use, copy, modify, merge, publish, distribute, sublicense, 7 | // and/or sell copies of the Software, and to permit persons to whom the 8 | // Software is furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 14 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 19 | // DEALINGS IN THE SOFTWARE. 20 | 21 | use crate::protocol::FloodsubMessage; 22 | use crate::Topic; 23 | use futures::channel::mpsc; 24 | use futures::StreamExt; 25 | use std::fmt; 26 | use std::sync::Arc; 27 | 28 | #[derive(Clone, Copy, Debug, Eq, PartialOrd, Ord)] 29 | pub struct SubId(u32); 30 | 31 | impl SubId { 32 | /// Create a random connection ID. 33 | pub(crate) fn random() -> Self { 34 | SubId(rand::random()) 35 | } 36 | } 37 | 38 | impl fmt::Display for SubId { 39 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 40 | write!(f, "{}", self.0) 41 | } 42 | } 43 | 44 | impl PartialEq for SubId { 45 | fn eq(&self, other: &Self) -> bool { 46 | self.0 == other.0 47 | } 48 | } 49 | 50 | // HashMap insert() required key impl Hash trait 51 | impl std::hash::Hash for SubId { 52 | fn hash(&self, hasher: &mut H) { 53 | hasher.write_u32(self.0); 54 | } 55 | } 56 | impl nohash_hasher::IsEnabled for SubId {} 57 | 58 | pub struct Subscription { 59 | id: SubId, 60 | topic: Topic, 61 | rx: mpsc::UnboundedReceiver>, 62 | cancel: mpsc::UnboundedSender<(Topic, SubId)>, 63 | } 64 | 65 | impl Subscription { 66 | pub fn new( 67 | id: SubId, 68 | topic: Topic, 69 | rx: mpsc::UnboundedReceiver>, 70 | cancel: mpsc::UnboundedSender<(Topic, SubId)>, 71 | ) -> Self { 72 | Subscription { id, topic, rx, cancel } 73 | } 74 | 75 | pub async fn next(&mut self) -> Option> { 76 | self.rx.next().await 77 | } 78 | 79 | pub fn cancel(&self) { 80 | let _ = self.cancel.unbounded_send((self.topic.clone(), self.id)); 81 | } 82 | } 83 | 84 | impl Drop for Subscription { 85 | fn drop(&mut self) { 86 | let _ = self.cancel.unbounded_send((self.topic.clone(), self.id)); 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /protocols/gossipsub/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # 0.1.0 [2021-05-11] 2 | 3 | - Initial release. 4 | -------------------------------------------------------------------------------- /protocols/gossipsub/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "libp2prs-gossipsub" 3 | description = "Gossipsub protocol for libp2p-rs" 4 | version = "0.4.0" 5 | authors = ["Netwarps Technologies admin@paradeum.com"] 6 | repository = "https://github.com/netwarps/libp2p-rs" 7 | keywords = ["peer-to-peer", "libp2p", "networking"] 8 | categories = ["network-programming", "asynchronous"] 9 | edition = "2018" 10 | 11 | [features] 12 | async-std = ["libp2prs-swarm/async-std", "libp2prs-runtime/async-std"] 13 | tokio = ["libp2prs-swarm/tokio", "libp2prs-runtime/tokio"] 14 | 15 | [dependencies] 16 | async-trait = "0.1" 17 | libp2prs-runtime = { path = "../../runtime", version = "0.4.0" } 18 | libp2prs-core = { path = "../../core", version = "0.4.0" } 19 | libp2prs-swarm = { path = "../../swarm", version = "0.4.0" } 20 | 21 | futures = { version = "0.3", features = ["std"], default-features = false } 22 | xcli = "0.5" 23 | bytes = "1.0" 24 | byteorder = "1.3.4" 25 | fnv = "1.0.7" 26 | wasm-timer = "0.2.4" 27 | unsigned-varint = "0.7.0" 28 | log = "0.4" 29 | prost = "0.7" 30 | rand = "0.7" 31 | smallvec = "1.6" 32 | nohash-hasher = "0.2" 33 | sha2 = "0.9" 34 | base64 = "0.13" 35 | hex_fmt = "0.3" 36 | regex = "1.4" 37 | lazy_static = "1.4" 38 | 39 | [dev-dependencies] 40 | env_logger = "0.8" 41 | libp2prs-mplex = { path = "../mplex", version = "0.4.0" } 42 | libp2prs-yamux = { path = "../yamux", version = "0.4.0" } 43 | libp2prs-secio = { path = "../secio", version = "0.4.0" } 44 | libp2prs-tcp = { path = "../../transports/tcp", version = "0.4.0", features = ["async-std"] } 45 | lazy_static = "1.4" 46 | quickcheck = "0.9" 47 | hex = "0.4.2" 48 | derive_builder = "0.10.0" 49 | 50 | 51 | [build-dependencies] 52 | prost-build = "0.7" 53 | -------------------------------------------------------------------------------- /protocols/gossipsub/build.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Parity Technologies (UK) Ltd. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a 4 | // copy of this software and associated documentation files (the "Software"), 5 | // to deal in the Software without restriction, including without limitation 6 | // the rights to use, copy, modify, merge, publish, distribute, sublicense, 7 | // and/or sell copies of the Software, and to permit persons to whom the 8 | // Software is furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 14 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 19 | // DEALINGS IN THE SOFTWARE. 20 | 21 | fn main() { 22 | prost_build::compile_protos(&["src/rpc.proto", "src/compat.proto"], &["src"]).unwrap(); 23 | } 24 | -------------------------------------------------------------------------------- /protocols/gossipsub/src/compat.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto2"; 2 | 3 | package compat.pb; 4 | 5 | message Message { 6 | optional bytes from = 1; 7 | optional bytes data = 2; 8 | optional bytes seqno = 3; 9 | repeated string topic_ids = 4; 10 | optional bytes signature = 5; 11 | optional bytes key = 6; 12 | } -------------------------------------------------------------------------------- /protocols/gossipsub/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Sigma Prime Pty Ltd. 2 | // Copyright 2021 Netwarps Ltd. 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a 5 | // copy of this software and associated documentation files (the "Software"), 6 | // to deal in the Software without restriction, including without limitation 7 | // the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 | // and/or sell copies of the Software, and to permit persons to whom the 9 | // Software is furnished to do so, subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 15 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 20 | // DEALINGS IN THE SOFTWARE. 21 | 22 | pub mod control; 23 | pub mod error; 24 | pub mod protocol; 25 | pub mod subscription; 26 | 27 | mod backoff; 28 | mod config; 29 | mod gossip_promises; 30 | pub mod gossipsub; 31 | // mod handler; 32 | mod mcache; 33 | mod peer_score; 34 | pub mod subscription_filter; 35 | pub mod time_cache; 36 | pub mod topic; 37 | mod transform; 38 | mod types; 39 | 40 | #[cfg(test)] 41 | extern crate derive_builder; 42 | 43 | #[allow(unused_mut)] 44 | #[allow(clippy::let_and_return)] 45 | pub mod cli; 46 | mod rpc_proto; 47 | 48 | // pub use self::behaviour::{Gossipsub, GossipsubEvent, MessageAuthenticity}; 49 | pub use self::transform::{DataTransform, IdentityTransform}; 50 | 51 | pub use self::config::{GossipsubConfig, GossipsubConfigBuilder, ValidationMode}; 52 | pub use self::peer_score::{ 53 | score_parameter_decay, score_parameter_decay_with_base, PeerScoreParams, PeerScoreThresholds, TopicScoreParams, 54 | }; 55 | pub use self::topic::{Hasher, Topic, TopicHash}; 56 | pub use self::types::{FastMessageId, GossipsubMessage, GossipsubRpc, MessageAcceptance, MessageId, RawGossipsubMessage}; 57 | use futures::channel::{mpsc, oneshot}; 58 | use std::fmt::{Display, Result}; 59 | use std::io; 60 | // pub type IdentTopic = Topic; 61 | // pub type Sha256Topic = Topic; 62 | 63 | #[derive(Debug)] 64 | pub enum GossipsubError { 65 | Io(io::Error), 66 | Closed, 67 | } 68 | 69 | impl std::error::Error for GossipsubError { 70 | fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { 71 | match self { 72 | GossipsubError::Io(err) => Some(err), 73 | GossipsubError::Closed => None, 74 | } 75 | } 76 | } 77 | 78 | impl Display for GossipsubError { 79 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result { 80 | match self { 81 | GossipsubError::Io(e) => write!(f, "i/o error: {}", e), 82 | GossipsubError::Closed => f.write_str("Gossipsub protocol is closed"), 83 | } 84 | } 85 | } 86 | 87 | impl From for GossipsubError { 88 | fn from(e: io::Error) -> Self { 89 | GossipsubError::Io(e) 90 | } 91 | } 92 | 93 | impl From for GossipsubError { 94 | fn from(_: mpsc::SendError) -> Self { 95 | GossipsubError::Closed 96 | } 97 | } 98 | 99 | impl From for GossipsubError { 100 | fn from(_: oneshot::Canceled) -> Self { 101 | GossipsubError::Closed 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /protocols/gossipsub/src/peer_score/tests.rs: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /protocols/gossipsub/src/rpc.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto2"; 2 | 3 | package gossipsub.pb; 4 | 5 | message RPC { 6 | repeated SubOpts subscriptions = 1; 7 | repeated Message publish = 2; 8 | 9 | message SubOpts { 10 | optional bool subscribe = 1; // subscribe or unsubscribe 11 | optional string topic_id = 2; 12 | } 13 | 14 | optional ControlMessage control = 3; 15 | } 16 | 17 | message Message { 18 | optional bytes from = 1; 19 | optional bytes data = 2; 20 | optional bytes seqno = 3; 21 | required string topic = 4; 22 | optional bytes signature = 5; 23 | optional bytes key = 6; 24 | } 25 | 26 | message ControlMessage { 27 | repeated ControlIHave ihave = 1; 28 | repeated ControlIWant iwant = 2; 29 | repeated ControlGraft graft = 3; 30 | repeated ControlPrune prune = 4; 31 | } 32 | 33 | message ControlIHave { 34 | optional string topic_id = 1; 35 | repeated bytes message_ids = 2; 36 | } 37 | 38 | message ControlIWant { 39 | repeated bytes message_ids= 1; 40 | } 41 | 42 | message ControlGraft { 43 | optional string topic_id = 1; 44 | } 45 | 46 | message ControlPrune { 47 | optional string topic_id = 1; 48 | repeated PeerInfo peers = 2; // gossipsub v1.1 PX 49 | optional uint64 backoff = 3; // gossipsub v1.1 backoff time (in seconds) 50 | } 51 | 52 | message PeerInfo { 53 | optional bytes peer_id = 1; 54 | optional bytes signed_peer_record = 2; 55 | } 56 | 57 | // topicID = hash(topicDescriptor); (not the topic.name) 58 | message TopicDescriptor { 59 | optional string name = 1; 60 | optional AuthOpts auth = 2; 61 | optional EncOpts enc = 3; 62 | 63 | message AuthOpts { 64 | optional AuthMode mode = 1; 65 | repeated bytes keys = 2; // root keys to trust 66 | 67 | enum AuthMode { 68 | NONE = 0; // no authentication, anyone can publish 69 | KEY = 1; // only messages signed by keys in the topic descriptor are accepted 70 | WOT = 2; // web of trust, certificates can allow publisher set to grow 71 | } 72 | } 73 | 74 | message EncOpts { 75 | optional EncMode mode = 1; 76 | repeated bytes key_hashes = 2; // the hashes of the shared keys used (salted) 77 | 78 | enum EncMode { 79 | NONE = 0; // no encryption, anyone can read 80 | SHAREDKEY = 1; // messages are encrypted with shared key 81 | WOT = 2; // web of trust, certificates can allow publisher set to grow 82 | } 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /protocols/gossipsub/src/rpc_proto.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Sigma Prime Pty Ltd. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a 4 | // copy of this software and associated documentation files (the "Software"), 5 | // to deal in the Software without restriction, including without limitation 6 | // the rights to use, copy, modify, merge, publish, distribute, sublicense, 7 | // and/or sell copies of the Software, and to permit persons to whom the 8 | // Software is furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 14 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 19 | // DEALINGS IN THE SOFTWARE. 20 | 21 | include!(concat!(env!("OUT_DIR"), "/gossipsub.pb.rs")); 22 | -------------------------------------------------------------------------------- /protocols/gossipsub/src/subscription.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Netwarps Ltd. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a 4 | // copy of this software and associated documentation files (the "Software"), 5 | // to deal in the Software without restriction, including without limitation 6 | // the rights to use, copy, modify, merge, publish, distribute, sublicense, 7 | // and/or sell copies of the Software, and to permit persons to whom the 8 | // Software is furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 14 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 19 | // DEALINGS IN THE SOFTWARE. 20 | 21 | use futures::channel::mpsc; 22 | use futures::StreamExt; 23 | use std::fmt; 24 | use std::sync::Arc; 25 | 26 | use crate::{GossipsubMessage, TopicHash}; 27 | // use crate::Topic; 28 | 29 | #[derive(Clone, Copy, Debug, Eq, PartialOrd, Ord)] 30 | pub struct SubId(u32); 31 | 32 | impl SubId { 33 | /// Create a random connection ID. 34 | pub(crate) fn random() -> Self { 35 | SubId(rand::random()) 36 | } 37 | } 38 | 39 | impl fmt::Display for SubId { 40 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 41 | write!(f, "{}", self.0) 42 | } 43 | } 44 | 45 | impl PartialEq for SubId { 46 | fn eq(&self, other: &Self) -> bool { 47 | self.0 == other.0 48 | } 49 | } 50 | 51 | // HashMap insert() required key impl Hash trait 52 | impl std::hash::Hash for SubId { 53 | fn hash(&self, hasher: &mut H) { 54 | hasher.write_u32(self.0); 55 | } 56 | } 57 | impl nohash_hasher::IsEnabled for SubId {} 58 | 59 | pub struct Subscription { 60 | id: SubId, 61 | topic: TopicHash, 62 | rx: mpsc::UnboundedReceiver>, 63 | cancel: mpsc::UnboundedSender<(TopicHash, SubId)>, 64 | } 65 | 66 | impl Subscription { 67 | pub fn new( 68 | id: SubId, 69 | topic: TopicHash, 70 | rx: mpsc::UnboundedReceiver>, 71 | cancel: mpsc::UnboundedSender<(TopicHash, SubId)>, 72 | ) -> Self { 73 | Subscription { id, topic, rx, cancel } 74 | } 75 | 76 | pub async fn next(&mut self) -> Option> { 77 | self.rx.next().await 78 | } 79 | 80 | pub fn cancel(&self) { 81 | let _ = self.cancel.unbounded_send((self.topic.clone(), self.id)); 82 | } 83 | } 84 | 85 | impl Drop for Subscription { 86 | fn drop(&mut self) { 87 | let _ = self.cancel.unbounded_send((self.topic.clone(), self.id)); 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /protocols/gossipsub/src/topic.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Sigma Prime Pty Ltd. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a 4 | // copy of this software and associated documentation files (the "Software"), 5 | // to deal in the Software without restriction, including without limitation 6 | // the rights to use, copy, modify, merge, publish, distribute, sublicense, 7 | // and/or sell copies of the Software, and to permit persons to whom the 8 | // Software is furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 14 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 19 | // DEALINGS IN THE SOFTWARE. 20 | 21 | use crate::rpc_proto; 22 | use base64::encode; 23 | use prost::Message; 24 | use sha2::{Digest, Sha256}; 25 | use std::fmt; 26 | 27 | /// A generic trait that can be extended for various hashing types for a topic. 28 | pub trait Hasher { 29 | /// The function that takes a topic string and creates a topic hash. 30 | fn hash(topic_string: String) -> TopicHash; 31 | } 32 | 33 | /// A type for representing topics who use the identity hash. 34 | #[derive(Debug, Clone)] 35 | pub struct IdentityHash {} 36 | impl Hasher for IdentityHash { 37 | /// Creates a [`TopicHash`] as a raw string. 38 | fn hash(topic_string: String) -> TopicHash { 39 | TopicHash { hash: topic_string } 40 | } 41 | } 42 | 43 | #[derive(Debug, Clone)] 44 | pub struct Sha256Hash {} 45 | impl Hasher for Sha256Hash { 46 | /// Creates a [`TopicHash`] by SHA256 hashing the topic then base64 encoding the 47 | /// hash. 48 | fn hash(topic_string: String) -> TopicHash { 49 | let topic_descripter = rpc_proto::TopicDescriptor { 50 | name: Some(topic_string), 51 | auth: None, 52 | enc: None, 53 | }; 54 | let mut bytes = Vec::with_capacity(topic_descripter.encoded_len()); 55 | topic_descripter.encode(&mut bytes).expect("buffer is large enough"); 56 | let hash = encode(Sha256::digest(&bytes).as_slice()); 57 | TopicHash { hash } 58 | } 59 | } 60 | 61 | #[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] 62 | pub struct TopicHash { 63 | /// The topic hash. Stored as a string to align with the protobuf API. 64 | hash: String, 65 | } 66 | 67 | impl TopicHash { 68 | pub fn from_raw(hash: impl Into) -> TopicHash { 69 | TopicHash { hash: hash.into() } 70 | } 71 | 72 | pub fn into_string(self) -> String { 73 | self.hash 74 | } 75 | 76 | pub fn as_str(&self) -> &str { 77 | &self.hash 78 | } 79 | } 80 | 81 | /// A gossipsub topic. 82 | #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] 83 | pub struct Topic { 84 | topic: String, 85 | phantom_data: std::marker::PhantomData, 86 | } 87 | 88 | impl From> for TopicHash { 89 | fn from(topic: Topic) -> TopicHash { 90 | topic.hash() 91 | } 92 | } 93 | 94 | impl Topic { 95 | pub fn new(topic: impl Into) -> Self { 96 | Topic { 97 | topic: topic.into(), 98 | phantom_data: std::marker::PhantomData, 99 | } 100 | } 101 | 102 | pub fn hash(&self) -> TopicHash { 103 | H::hash(self.topic.clone()) 104 | } 105 | } 106 | 107 | impl fmt::Display for Topic { 108 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 109 | write!(f, "{}", self.topic) 110 | } 111 | } 112 | 113 | impl fmt::Display for TopicHash { 114 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 115 | write!(f, "{}", self.hash) 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /protocols/gossipsub/src/transform.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Sigma Prime Pty Ltd. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a 4 | // copy of this software and associated documentation files (the "Software"), 5 | // to deal in the Software without restriction, including without limitation 6 | // the rights to use, copy, modify, merge, publish, distribute, sublicense, 7 | // and/or sell copies of the Software, and to permit persons to whom the 8 | // Software is furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 14 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 19 | // DEALINGS IN THE SOFTWARE. 20 | 21 | //! This trait allows of extended user-level decoding that can apply to message-data before a 22 | //! message-id is calculated. 23 | //! 24 | //! This is primarily designed to allow applications to implement their own custom compression 25 | //! algorithms that can be topic-specific. Once the raw data is transformed the message-id is then 26 | //! calculated, allowing for applications to employ message-id functions post compression. 27 | 28 | use crate::{GossipsubMessage, RawGossipsubMessage, TopicHash}; 29 | 30 | /// A general trait of transforming a [`RawGossipsubMessage`] into a [`GossipsubMessage`]. The 31 | /// [`RawGossipsubMessage`] is obtained from the wire and the [`GossipsubMessage`] is used to 32 | /// calculate the [`crate::MessageId`] of the message and is what is sent to the application. 33 | /// 34 | /// The inbound/outbound transforms must be inverses. Applying the inbound transform and then the 35 | /// outbound transform MUST leave the underlying data un-modified. 36 | /// 37 | /// By default, this is the identity transform for all fields in [`GossipsubMessage`]. 38 | pub trait DataTransform { 39 | /// Takes a [`RawGossipsubMessage`] received and converts it to a [`GossipsubMessage`]. 40 | fn inbound_transform(&self, raw_message: RawGossipsubMessage) -> Result; 41 | 42 | /// Takes the data to be published (a topic and associated data) transforms the data. The 43 | /// transformed data will then be used to create a [`crate::RawGossipsubMessage`] to be sent to peers. 44 | fn outbound_transform(&self, topic: &TopicHash, data: Vec) -> Result, std::io::Error>; 45 | } 46 | 47 | /// The default transform, the raw data is propagated as is to the application layer gossipsub. 48 | #[derive(Default, Clone)] 49 | pub struct IdentityTransform; 50 | 51 | impl DataTransform for IdentityTransform { 52 | fn inbound_transform(&self, raw_message: RawGossipsubMessage) -> Result { 53 | Ok(GossipsubMessage { 54 | source: raw_message.source, 55 | data: raw_message.data, 56 | sequence_number: raw_message.sequence_number, 57 | topic: raw_message.topic, 58 | }) 59 | } 60 | 61 | fn outbound_transform(&self, _topic: &TopicHash, data: Vec) -> Result, std::io::Error> { 62 | Ok(data) 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /protocols/kad/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "libp2prs-kad" 3 | edition = "2018" 4 | description = "Kademlia protocol for libp2p" 5 | version = "0.4.0" 6 | authors = ["Netwarps Technologies admin@paradeum.com"] 7 | license = "MIT" 8 | repository = "https://github.com/netwarps/libp2p-rs" 9 | keywords = ["peer-to-peer", "libp2p", "kad", "dht"] 10 | categories = ["network-programming", "asynchronous"] 11 | 12 | [features] 13 | async-std = ["libp2prs-swarm/async-std", "libp2prs-runtime/async-std"] 14 | tokio = ["libp2prs-swarm/tokio", "libp2prs-runtime/tokio"] 15 | 16 | [dependencies] 17 | arrayvec = "0.5.1" 18 | bytes = "0.5" 19 | fnv = "1.0" 20 | futures = { version = "0.3", features = ["std"], default-features = false } 21 | log = "0.4" 22 | prost = "0.6" 23 | #uint = "0.8" 24 | primitive-types = "0.8" 25 | rand = "0.7" 26 | sha2 = "0.9.1" 27 | smallvec = "1.0" 28 | void = "1.0" 29 | async-trait = "0.1" 30 | xcli = "0.5" 31 | #xcli = { git = "https://github.com/kingwel-xie/xcli-rs.git", branch = "master"} 32 | 33 | libp2prs-runtime = { path = "../../runtime", version = "0.4.0" } 34 | libp2prs-core = { path = "../../core", version = "0.4.0" } 35 | libp2prs-swarm = { path = "../../swarm", version = "0.4.0" } 36 | 37 | 38 | [dev-dependencies] 39 | env_logger = "0.8" 40 | libp2prs-mplex = { path = "../mplex", version = "0.4.0" } 41 | libp2prs-yamux = { path = "../yamux", version = "0.4.0" } 42 | libp2prs-secio = { path = "../secio", version = "0.4.0" } 43 | libp2prs-plaintext = { path = "../plaintext", version = "0.4.0" } 44 | 45 | libp2prs-tcp = { path = "../../transports/tcp", version = "0.4.0", features = ["async-std"] } 46 | lazy_static = "1.4" 47 | quickcheck = "0.9" 48 | 49 | [build-dependencies] 50 | prost-build = "0.6" 51 | 52 | -------------------------------------------------------------------------------- /protocols/kad/README.md: -------------------------------------------------------------------------------- 1 | # libp2prs-kad 2 | 3 | 4 | Comparison of kad implementations between rust-libp2p and go-libp2p: 5 | 6 | ## Kbuckets, AKA. routing table 7 | 8 | ### go 9 | 10 | + buckets are expanded on demand 11 | + no multiaddr, depends on peerstore 12 | + insertion: 13 | * initialization, to fill kbuckets with all connected peers 14 | * fix low peers 15 | * when a remote peer is sending RPC to us 16 | * when we iteratively query a remote peer successfully 17 | 18 | // TryAddPeer tries to add a peer to the Routing table. 19 | // If the peer ALREADY exists in the Routing Table and has been queried before, this call is a no-op. 20 | // If the peer ALREADY exists in the Routing Table but hasn't been queried before, we set it's LastUsefulAt value to 21 | // the current time. This needs to done because we don't mark peers as "Useful"(by setting the LastUsefulAt value) 22 | // when we first connect to them. 23 | // 24 | // If the peer is a queryPeer i.e. we queried it or it queried us, we set the LastSuccessfulOutboundQuery to the current time. 25 | // If the peer is just a peer that we connect to/it connected to us without any DHT query, we consider it as having 26 | // no LastSuccessfulOutboundQuery. 27 | // 28 | // 29 | // If the logical bucket to which the peer belongs is full and it's not the last bucket, we try to replace an existing peer 30 | // whose LastSuccessfulOutboundQuery is above the maximum allowed threshold in that bucket with the new peer. 31 | // If no such peer exists in that bucket, we do NOT add the peer to the Routing Table and return error "ErrPeerRejectedNoCapacity". 32 | 33 | // It returns a boolean value set to true if the peer was newly added to the Routing Table, false otherwise. 34 | // It also returns any error that occurred while adding the peer to the Routing Table. If the error is not nil, 35 | // the boolean value will ALWAYS be false i.e. the peer wont be added to the Routing Table it it's not already there. 36 | // 37 | // A return value of false with error=nil indicates that the peer ALREADY exists in the Routing Table. 38 | + deletion 39 | * when a remote peer is found not responding to an outbound query 40 | * refresh manager: remote peer can not be connected 41 | * handlePeerChangeEvent: remote is deemed as not qualified as a Kad peer 42 | 43 | ### rust 44 | 45 | + all buckets are initialized in the beginning 46 | + multiaddr embedded in kbuckets 47 | + insertion: when Kad protocol is confirmed with remote peer -> inboung/outbound protocol upgrade done 48 | * insert if there is room, pending if there is not 49 | + KademliaBucketInserts decide how to insert: OnConnected or Manual 50 | * update the addresses and status if the peer is already or pending in RT 51 | + deletion: manual only 52 | + update: when peer is found disconnected 53 | * always update the addresses and status 54 | + NoeStatus: impact how to insert a new peer into RT 55 | 56 | 57 | -------------------------------------------------------------------------------- /protocols/kad/build.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Netwarps Ltd. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a 4 | // copy of this software and associated documentation files (the "Software"), 5 | // to deal in the Software without restriction, including without limitation 6 | // the rights to use, copy, modify, merge, publish, distribute, sublicense, 7 | // and/or sell copies of the Software, and to permit persons to whom the 8 | // Software is furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 14 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 19 | // DEALINGS IN THE SOFTWARE. 20 | 21 | fn main() { 22 | prost_build::compile_protos(&["src/dht.proto"], &["src"]).unwrap(); 23 | } 24 | -------------------------------------------------------------------------------- /protocols/kad/examples/bucket.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Netwarps Ltd. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a 4 | // copy of this software and associated documentation files (the "Software"), 5 | // to deal in the Software without restriction, including without limitation 6 | // the rights to use, copy, modify, merge, publish, distribute, sublicense, 7 | // and/or sell copies of the Software, and to permit persons to whom the 8 | // Software is furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 14 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 19 | // DEALINGS IN THE SOFTWARE. 20 | 21 | // This test is to generate many random peers to fit into k-buckets. We shall 22 | // see it is very hard to get the closer peers... 23 | 24 | use libp2prs_core::PeerId; 25 | use libp2prs_kad::kbucket::{Entry, KBucketsTable, Key}; 26 | 27 | fn main() { 28 | let local_key = Key::from(PeerId::random()); 29 | let mut table = KBucketsTable::, ()>::new(local_key); 30 | let mut count = 0; 31 | let mut lc = 0; 32 | loop { 33 | lc += 1; 34 | if count == 1000 { 35 | break; 36 | } 37 | 38 | if lc % 100000 == 0 { 39 | println!("lc={} c={}", lc, count); 40 | print_table(&mut table); 41 | } 42 | let key = Key::from(PeerId::random()); 43 | if let Entry::Absent(mut e) = table.entry(&key) { 44 | if e.insert(()) { 45 | count += 1 46 | } else { 47 | continue; 48 | } 49 | } else { 50 | panic!("entry exists") 51 | } 52 | } 53 | } 54 | 55 | fn print_table(table: &mut KBucketsTable, ()>) { 56 | let view = table 57 | .iter() 58 | .filter(|k| !k.is_empty()) 59 | .map(|k| { 60 | let index = k.index(); 61 | 62 | (index, k.num_entries()) 63 | }) 64 | .collect::>(); 65 | 66 | println!("{:?}", view); 67 | } 68 | -------------------------------------------------------------------------------- /protocols/kad/examples/task_limiter.rs: -------------------------------------------------------------------------------- 1 | use libp2prs_runtime::limit::TaskLimiter; 2 | use libp2prs_runtime::task; 3 | use log::info; 4 | use std::num::NonZeroUsize; 5 | use std::time::Duration; 6 | 7 | fn main() { 8 | env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("info")).init(); 9 | 10 | let mut limiter = TaskLimiter::new(NonZeroUsize::new(5).unwrap()); 11 | 12 | for i in 0..10 { 13 | limiter.spawn(async move { 14 | info!("job {} started...", i); 15 | task::sleep(Duration::from_secs(5)).await; 16 | info!("job {} stopped", i); 17 | Ok::<(), ()>(()) 18 | }); 19 | } 20 | 21 | task::block_on(async { 22 | task::sleep(Duration::from_secs(1)).await; 23 | //let stat = limiter.shutdown().await; 24 | let stat = limiter.wait().await; 25 | info!("stat={:?}", stat); 26 | }) 27 | } 28 | -------------------------------------------------------------------------------- /protocols/kad/src/addresses.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Netwarps Ltd. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a 4 | // copy of this software and associated documentation files (the "Software"), 5 | // to deal in the Software without restriction, including without limitation 6 | // the rights to use, copy, modify, merge, publish, distribute, sublicense, 7 | // and/or sell copies of the Software, and to permit persons to whom the 8 | // Software is furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 14 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 19 | // DEALINGS IN THE SOFTWARE. 20 | 21 | use std::time::Instant; 22 | 23 | /// The information of a peer in Kad routing table. 24 | #[derive(Clone, Debug)] 25 | pub struct PeerInfo { 26 | /// The time instant at which we talk to the remote peer. 27 | /// Sets to `Some` if it is deemed to be alive. Otherwise, 28 | /// it is set to `None` 29 | aliveness: Option, 30 | 31 | /// The time this peer was added to the routing table. 32 | added_at: Instant, 33 | 34 | /// Permanent entry, never replaced by health check. 35 | permanent: bool, 36 | } 37 | 38 | impl PeerInfo { 39 | pub(crate) fn new(aliveness: bool, permanent: bool) -> Self { 40 | Self { 41 | aliveness: if aliveness { Some(Instant::now()) } else { None }, 42 | added_at: Instant::now(), 43 | permanent, 44 | } 45 | } 46 | 47 | pub(crate) fn set_aliveness(&mut self, aliveness: Option) { 48 | self.aliveness = aliveness; 49 | } 50 | 51 | pub(crate) fn get_aliveness(&self) -> Option { 52 | self.aliveness 53 | } 54 | 55 | pub(crate) fn is_permanent(&self) -> bool { 56 | self.permanent 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /protocols/kad/src/dht.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | package dht.pb; 3 | 4 | // Record represents a dht record that contains a value 5 | // for a key value pair 6 | message Record { 7 | // The key that references this record 8 | bytes key = 1; 9 | 10 | // The actual value this record is storing 11 | bytes value = 2; 12 | 13 | // Note: These fields were removed from the Record message 14 | // hash of the authors public key 15 | //optional string author = 3; 16 | // A PKI signature for the key+value+author 17 | //optional bytes signature = 4; 18 | 19 | // Time the record was received, set by receiver, currently ignored. 20 | string timeReceived = 5; 21 | 22 | // The original publisher of the record. 23 | // Currently specific to libp2p-rs. 24 | bytes publisher = 666; 25 | }; 26 | 27 | message Message { 28 | enum MessageType { 29 | PUT_VALUE = 0; 30 | GET_VALUE = 1; 31 | ADD_PROVIDER = 2; 32 | GET_PROVIDERS = 3; 33 | FIND_NODE = 4; 34 | PING = 5; 35 | } 36 | 37 | enum ConnectionType { 38 | // sender does not have a connection to peer, and no extra information (default) 39 | NOT_CONNECTED = 0; 40 | 41 | // sender has a live connection to peer 42 | CONNECTED = 1; 43 | 44 | // sender recently connected to peer 45 | CAN_CONNECT = 2; 46 | 47 | // sender recently tried to connect to peer repeatedly but failed to connect 48 | // ("try" here is loose, but this should signal "made strong effort, failed") 49 | CANNOT_CONNECT = 3; 50 | } 51 | 52 | message Peer { 53 | // ID of a given peer. 54 | bytes id = 1; 55 | 56 | // multiaddrs for a given peer 57 | repeated bytes addrs = 2; 58 | 59 | // used to signal the sender's connection capabilities to the peer 60 | ConnectionType connection = 3; 61 | } 62 | 63 | // defines what type of message it is. 64 | MessageType type = 1; 65 | 66 | // defines what coral cluster level this query/response belongs to. 67 | // in case we want to implement coral's cluster rings in the future. 68 | int32 clusterLevelRaw = 10; // NOT USED 69 | 70 | // Used to specify the key associated with this message. 71 | // PUT_VALUE, GET_VALUE, ADD_PROVIDER, GET_PROVIDERS 72 | bytes key = 2; 73 | 74 | // Used to return a value 75 | // PUT_VALUE, GET_VALUE 76 | Record record = 3; 77 | 78 | // Used to return peers closer to a key in a query 79 | // GET_VALUE, GET_PROVIDERS, FIND_NODE 80 | repeated Peer closerPeers = 8; 81 | 82 | // Used to return Providers 83 | // GET_VALUE, ADD_PROVIDER, GET_PROVIDERS 84 | repeated Peer providerPeers = 9; 85 | } 86 | -------------------------------------------------------------------------------- /protocols/mdns/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "libp2prs-mdns" 3 | edition = "2018" 4 | description = "mdns protocol for libp2p" 5 | version = "0.4.0" 6 | authors = ["Netwarps Technologies admin@paradeum.com"] 7 | license = "MIT" 8 | repository = "https://github.com/netwarps/libp2p-rs" 9 | keywords = ["peer-to-peer", "libp2p"] 10 | categories = ["network-programming", "asynchronous"] 11 | 12 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 13 | 14 | [features] 15 | async-std = ["libp2prs-runtime/async-std"] 16 | tokio = ["libp2prs-runtime/tokio"] 17 | 18 | [dependencies] 19 | data-encoding = "2.0" 20 | dns-parser = "0.8" 21 | either = "1.5.3" 22 | futures = { version = "0.3", features = ["std"], default-features = false } 23 | futures-timer = "3.0.2" 24 | lazy_static = "1.4" 25 | log = "0.4" 26 | net2 = "0.2" 27 | nohash-hasher = "0.2" 28 | rand = "0.7" 29 | smallvec = "1.0" 30 | libp2prs-core = { path = "../../core", version = "0.4.0" } 31 | libp2prs-runtime = { path = "../../runtime", version = "0.4.0" } 32 | 33 | [dev-dependencies] 34 | env_logger = "0.8" 35 | quickcheck = "0.9" -------------------------------------------------------------------------------- /protocols/mdns/README.md: -------------------------------------------------------------------------------- 1 | # libp2prs-mdns 2 | 3 | This is the experimental mdns implementation for [libp2p-rs](https://github.com/netwarps/libp2p-rs). 4 | 5 | # usage 6 | refer to examples/mdns_simple.rs 7 | 8 | -------------------------------------------------------------------------------- /protocols/mdns/examples/mdns_simple.rs: -------------------------------------------------------------------------------- 1 | use libp2prs_runtime::task; 2 | 3 | use libp2prs_core::identity::Keypair; 4 | use libp2prs_core::Multiaddr; 5 | use libp2prs_mdns::service::MdnsService; 6 | use libp2prs_mdns::{AddrInfo, MdnsConfig, Notifee}; 7 | use std::time::Duration; 8 | 9 | pub struct DiscoveryNotifee {} 10 | 11 | impl Notifee for DiscoveryNotifee { 12 | fn handle_peer_found(&mut self, peer: AddrInfo) { 13 | log::info!("Discovered peer {}", peer); 14 | } 15 | } 16 | 17 | fn main() { 18 | env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("info")).init(); 19 | task::block_on(async { 20 | let pid = Keypair::generate_ed25519().public().into_peer_id(); 21 | let listen_addr: Multiaddr = "/ip4/0.0.0.0/tcp/0".parse().unwrap(); 22 | let config = MdnsConfig::new(pid, vec![listen_addr], false); 23 | let service = MdnsService::new(config); 24 | let mut control = service.control(); 25 | 26 | service.start(); 27 | control.register_notifee(Box::new(DiscoveryNotifee {})).await; 28 | 29 | loop { 30 | task::sleep(Duration::from_secs(120)).await; 31 | } 32 | }); 33 | } 34 | -------------------------------------------------------------------------------- /protocols/mdns/src/control.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Netwarps Ltd. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a 4 | // copy of this software and associated documentation files (the "Software"), 5 | // to deal in the Software without restriction, including without limitation 6 | // the rights to use, copy, modify, merge, publish, distribute, sublicense, 7 | // and/or sell copies of the Software, and to permit persons to whom the 8 | // Software is furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 14 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 19 | // DEALINGS IN THE SOFTWARE. 20 | 21 | use crate::service::ControlCommand; 22 | use crate::INotifiee; 23 | use futures::channel::{mpsc, oneshot}; 24 | use futures::SinkExt; 25 | use std::fmt; 26 | 27 | #[derive(Clone, Copy, Debug, Eq, PartialOrd, Ord)] 28 | pub struct RegId(u32); 29 | 30 | impl RegId { 31 | /// Create a random connection ID. 32 | pub(crate) fn random() -> Self { 33 | RegId(rand::random()) 34 | } 35 | } 36 | 37 | impl fmt::Display for RegId { 38 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 39 | write!(f, "{}", self.0) 40 | } 41 | } 42 | 43 | impl PartialEq for RegId { 44 | fn eq(&self, other: &Self) -> bool { 45 | self.0 == other.0 46 | } 47 | } 48 | 49 | // HashMap insert() required key impl Hash trait 50 | impl std::hash::Hash for RegId { 51 | fn hash(&self, hasher: &mut H) { 52 | hasher.write_u32(self.0); 53 | } 54 | } 55 | impl nohash_hasher::IsEnabled for RegId {} 56 | 57 | pub struct Control { 58 | tx: mpsc::Sender, 59 | } 60 | 61 | impl Control { 62 | pub fn new(tx: mpsc::Sender) -> Self { 63 | Control { tx } 64 | } 65 | 66 | pub async fn register_notifee(&mut self, noti: INotifiee) -> RegId { 67 | let (tx, rx) = oneshot::channel(); 68 | let cmd = ControlCommand::RegisterNotifee(noti, tx); 69 | self.tx.send(cmd).await.expect("send RegisterNotifee failed"); 70 | rx.await.expect("recv RegisterNotifee failed") 71 | } 72 | 73 | pub async fn unregister_notifee(&mut self, id: RegId) { 74 | let _ = self.tx.send(ControlCommand::UnregisterNotifee(id)).await; 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /protocols/mdns/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Netwarps Ltd. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a 4 | // copy of this software and associated documentation files (the "Software"), 5 | // to deal in the Software without restriction, including without limitation 6 | // the rights to use, copy, modify, merge, publish, distribute, sublicense, 7 | // and/or sell copies of the Software, and to permit persons to whom the 8 | // Software is furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 14 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 19 | // DEALINGS IN THE SOFTWARE. 20 | 21 | //! mDNS is a protocol defined by [RFC 6762](https://tools.ietf.org/html/rfc6762) that allows 22 | //! querying nodes that correspond to a certain domain name. 23 | //! 24 | //! In the context of libp2p, the mDNS protocol is used to discover other nodes on the local 25 | //! network that support libp2p. 26 | //! 27 | 28 | use libp2prs_core::{Multiaddr, PeerId}; 29 | 30 | /// Hardcoded name of the mDNS service. Part of the mDNS libp2p specifications. 31 | const SERVICE_NAME: &[u8] = b"_p2p._udp.local"; 32 | /// Hardcoded name of the service used for DNS-SD. 33 | const META_QUERY_SERVICE: &[u8] = b"_services._dns-sd._udp.local"; 34 | 35 | pub mod control; 36 | mod dns; 37 | pub mod service; 38 | 39 | use smallvec::alloc::fmt::Formatter; 40 | use std::fmt; 41 | 42 | pub struct MdnsConfig { 43 | /// local Peer ID 44 | local_peer: PeerId, 45 | 46 | /// List of multiaddresses we're listening on. 47 | listened_addrs: Vec, 48 | 49 | /// Whether we send queries on the network at all. 50 | /// Note that we still need to have an interval for querying, as we need to wake up the socket 51 | /// regularly to recover from errors. Otherwise we could simply use an `Option`. 52 | silent: bool, 53 | } 54 | 55 | impl MdnsConfig { 56 | pub fn new(local_peer: PeerId, listened_addrs: Vec, silent: bool) -> Self { 57 | MdnsConfig { 58 | local_peer, 59 | listened_addrs, 60 | silent, 61 | } 62 | } 63 | } 64 | 65 | #[derive(Clone)] 66 | pub struct AddrInfo { 67 | pub pid: PeerId, 68 | pub addrs: Vec, 69 | } 70 | 71 | impl AddrInfo { 72 | pub fn new(pid: PeerId, addrs: Vec) -> Self { 73 | AddrInfo { pid, addrs } 74 | } 75 | 76 | pub fn get_peer(&self) -> &PeerId { 77 | &self.pid 78 | } 79 | 80 | pub fn get_addrs(&self) -> &[Multiaddr] { 81 | &self.addrs 82 | } 83 | } 84 | 85 | impl fmt::Debug for AddrInfo { 86 | fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { 87 | write!(f, "(AddrInfo {} {:?})", self.pid, self.addrs,) 88 | } 89 | } 90 | 91 | impl fmt::Display for AddrInfo { 92 | fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { 93 | write!(f, "(AddrInfo {} {:?})", self.pid, self.addrs,) 94 | } 95 | } 96 | 97 | pub trait Notifee { 98 | fn handle_peer_found(&mut self, _discovered: AddrInfo) {} 99 | } 100 | 101 | pub type INotifiee = Box; 102 | -------------------------------------------------------------------------------- /protocols/mplex/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "libp2prs-mplex" 3 | version = "0.4.0" 4 | license = "MIT" 5 | description = "Mplex multiplexing protocol for libp2p" 6 | authors = ["Netwarps Technologies admin@paradeum.com"] 7 | repository = "https://github.com/netwarps/libp2p-rs" 8 | keywords = ["peer-to-peer", "libp2p", "networking"] 9 | categories = ["network-programming", "asynchronous"] 10 | edition = "2018" 11 | 12 | [dependencies] 13 | futures = { version = "0.3", features = ["std"], default-features = false } 14 | libp2prs-core = { path = "../../core", version = "0.4.0" } 15 | nohash-hasher = "0.2" 16 | unsigned-varint = "0.4" 17 | async-trait = "0.1" 18 | bytes = "0.5.6" 19 | log = "0.4.8" 20 | rand = "0.7" 21 | futures-timer = "3" 22 | parking_lot = "0.11" 23 | 24 | [dev-dependencies] 25 | env_logger = "0.8" 26 | criterion = "0.3" 27 | libp2prs-runtime = { path = "../../runtime", version = "0.4.0", features = ["async-std"] } 28 | 29 | [dev-dependencies.quickcheck] 30 | version = "0.9" -------------------------------------------------------------------------------- /protocols/mplex/src/connection/control.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Netwarps Ltd. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a 4 | // copy of this software and associated documentation files (the "Software"), 5 | // to deal in the Software without restriction, including without limitation 6 | // the rights to use, copy, modify, merge, publish, distribute, sublicense, 7 | // and/or sell copies of the Software, and to permit persons to whom the 8 | // Software is furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 14 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 19 | // DEALINGS IN THE SOFTWARE. 20 | 21 | use futures::{ 22 | channel::{mpsc, oneshot}, 23 | SinkExt, 24 | }; 25 | 26 | use crate::{ 27 | connection::{stream::Stream, ControlCommand}, 28 | error::ConnectionError, 29 | }; 30 | 31 | pub struct Control { 32 | sender: mpsc::Sender, 33 | } 34 | 35 | type Result = std::result::Result; 36 | 37 | impl Control { 38 | pub fn new(sender: mpsc::Sender) -> Self { 39 | Control { sender } 40 | } 41 | 42 | /// Open a new stream to the remote. 43 | pub async fn open_stream(&mut self) -> Result { 44 | let (tx, rx) = oneshot::channel(); 45 | self.sender.send(ControlCommand::OpenStream(tx)).await?; 46 | rx.await? 47 | } 48 | 49 | /// Accept a new stream from the remote. 50 | pub async fn accept_stream(&mut self) -> Result { 51 | let (tx, rx) = oneshot::channel(); 52 | self.sender.send(ControlCommand::AcceptStream(tx)).await?; 53 | rx.await? 54 | } 55 | 56 | /// Close the connection. 57 | pub async fn close(&mut self) -> Result<()> { 58 | let (tx, rx) = oneshot::channel(); 59 | if self.sender.send(ControlCommand::CloseConnection(tx)).await.is_err() { 60 | // The receiver is closed which means the connection is already closed. 61 | return Ok(()); 62 | } 63 | // A dropped `oneshot::Sender` means the `Connection` is gone, 64 | // so we do not treat receive errors differently here. 65 | let _ = rx.await; 66 | Ok(()) 67 | } 68 | } 69 | 70 | impl Clone for Control { 71 | fn clone(&self) -> Self { 72 | Control { 73 | sender: self.sender.clone(), 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /protocols/mplex/src/error.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Netwarps Ltd. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a 4 | // copy of this software and associated documentation files (the "Software"), 5 | // to deal in the Software without restriction, including without limitation 6 | // the rights to use, copy, modify, merge, publish, distribute, sublicense, 7 | // and/or sell copies of the Software, and to permit persons to whom the 8 | // Software is furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 14 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 19 | // DEALINGS IN THE SOFTWARE. 20 | 21 | use crate::frame::FrameDecodeError; 22 | 23 | /// The various error cases a connection may encounter. 24 | #[non_exhaustive] 25 | #[derive(Debug)] 26 | pub enum ConnectionError { 27 | /// An underlying I/O error occured. 28 | Io(std::io::Error), 29 | /// Decoding a Yamux message frame failed. 30 | Decode(FrameDecodeError), 31 | /// The whole range of stream IDs has been used up. 32 | NoMoreStreamIds, 33 | /// An operation fails because the connection is closed. 34 | Closed, 35 | /// Too many streams are open, so no further ones can be opened at this time. 36 | TooManyStreams, 37 | } 38 | 39 | impl std::fmt::Display for ConnectionError { 40 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 41 | match self { 42 | ConnectionError::Io(e) => write!(f, "i/o error: {}", e), 43 | ConnectionError::Decode(e) => write!(f, "decode error: {}", e), 44 | ConnectionError::NoMoreStreamIds => f.write_str("number of stream ids has been exhausted"), 45 | ConnectionError::Closed => f.write_str("connection is closed"), 46 | ConnectionError::TooManyStreams => f.write_str("maximum number of streams reached"), 47 | } 48 | } 49 | } 50 | 51 | impl std::error::Error for ConnectionError { 52 | fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { 53 | match self { 54 | ConnectionError::Io(e) => Some(e), 55 | ConnectionError::Decode(e) => Some(e), 56 | ConnectionError::NoMoreStreamIds | ConnectionError::Closed | ConnectionError::TooManyStreams => None, 57 | } 58 | } 59 | } 60 | 61 | impl From for ConnectionError { 62 | fn from(e: std::io::Error) -> Self { 63 | ConnectionError::Io(e) 64 | } 65 | } 66 | 67 | impl From for ConnectionError { 68 | fn from(e: FrameDecodeError) -> Self { 69 | ConnectionError::Decode(e) 70 | } 71 | } 72 | 73 | impl From for ConnectionError { 74 | fn from(_: futures::channel::mpsc::SendError) -> Self { 75 | ConnectionError::Closed 76 | } 77 | } 78 | 79 | impl From for ConnectionError { 80 | fn from(_: futures::channel::oneshot::Canceled) -> Self { 81 | ConnectionError::Closed 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /protocols/mplex/src/frame.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Netwarps Ltd. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a 4 | // copy of this software and associated documentation files (the "Software"), 5 | // to deal in the Software without restriction, including without limitation 6 | // the rights to use, copy, modify, merge, publish, distribute, sublicense, 7 | // and/or sell copies of the Software, and to permit persons to whom the 8 | // Software is furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 14 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 19 | // DEALINGS IN THE SOFTWARE. 20 | 21 | pub(crate) mod header; 22 | pub(crate) mod io; 23 | mod length_delimited; 24 | 25 | pub(crate) use header::{Header, StreamID, Tag}; 26 | pub use io::FrameDecodeError; 27 | 28 | /// A Yamux message frame consisting of header and body. 29 | #[derive(Clone, Debug, PartialEq, Eq)] 30 | pub struct Frame { 31 | header: Header, 32 | body: Vec, 33 | } 34 | 35 | impl Frame { 36 | pub fn header(&self) -> &Header { 37 | &self.header 38 | } 39 | 40 | pub fn stream_id(&self) -> StreamID { 41 | self.header.stream_id() 42 | } 43 | 44 | pub fn body(self) -> Vec { 45 | self.body 46 | } 47 | 48 | // new stream frame 49 | pub fn new_stream_frame(stream_id: StreamID, body: &[u8]) -> Self { 50 | Frame { 51 | header: Header::new(stream_id, Tag::NewStream), 52 | body: body.to_vec(), 53 | } 54 | } 55 | 56 | // message frame 57 | pub fn message_frame(stream_id: StreamID, body: &[u8]) -> Self { 58 | Frame { 59 | header: Header::new(stream_id, Tag::Message), 60 | body: body.to_vec(), 61 | } 62 | } 63 | 64 | // close frame 65 | pub fn close_frame(stream_id: StreamID) -> Self { 66 | Frame { 67 | header: Header::new(stream_id, Tag::Close), 68 | body: Vec::new(), 69 | } 70 | } 71 | 72 | // reset frame 73 | pub fn reset_frame(stream_id: StreamID) -> Self { 74 | Frame { 75 | header: Header::new(stream_id, Tag::Reset), 76 | body: Vec::new(), 77 | } 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /protocols/mplex/src/pause.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Netwarps Ltd. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a 4 | // copy of this software and associated documentation files (the "Software"), 5 | // to deal in the Software without restriction, including without limitation 6 | // the rights to use, copy, modify, merge, publish, distribute, sublicense, 7 | // and/or sell copies of the Software, and to permit persons to whom the 8 | // Software is furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 14 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 19 | // DEALINGS IN THE SOFTWARE. 20 | 21 | use futures::{prelude::*, stream::FusedStream}; 22 | use std::{ 23 | pin::Pin, 24 | task::{Context, Poll, Waker}, 25 | }; 26 | 27 | /// Wraps a [`futures::stream::Stream`] and adds the ability to pause it. 28 | /// 29 | /// When pausing the stream, any call to `poll_next` will return 30 | /// `Poll::Pending` and the `Waker` will be saved (only the most recent 31 | /// one). When unpaused, the waker will be notified and the next call 32 | /// to `poll_next` can proceed as normal. 33 | #[derive(Debug)] 34 | pub(crate) struct Pausable { 35 | paused: bool, 36 | stream: S, 37 | waker: Option, 38 | } 39 | 40 | impl Pausable { 41 | pub(crate) fn new(stream: S) -> Self { 42 | Pausable { 43 | paused: false, 44 | stream, 45 | waker: None, 46 | } 47 | } 48 | 49 | pub(crate) fn is_paused(&mut self) -> bool { 50 | self.paused 51 | } 52 | 53 | pub(crate) fn pause(&mut self) { 54 | self.paused = true 55 | } 56 | 57 | pub(crate) fn unpause(&mut self) { 58 | self.paused = false; 59 | if let Some(w) = self.waker.take() { 60 | w.wake() 61 | } 62 | } 63 | 64 | pub(crate) fn stream(&mut self) -> &mut S { 65 | &mut self.stream 66 | } 67 | } 68 | 69 | impl Stream for Pausable { 70 | type Item = S::Item; 71 | 72 | fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll> { 73 | if !self.paused { 74 | return self.stream.poll_next_unpin(cx); 75 | } 76 | self.waker = Some(cx.waker().clone()); 77 | Poll::Pending 78 | } 79 | 80 | fn size_hint(&self) -> (usize, Option) { 81 | self.stream.size_hint() 82 | } 83 | } 84 | 85 | impl FusedStream for Pausable { 86 | fn is_terminated(&self) -> bool { 87 | self.stream.is_terminated() 88 | } 89 | } 90 | 91 | #[cfg(test)] 92 | mod tests { 93 | use super::Pausable; 94 | use futures::prelude::*; 95 | 96 | #[test] 97 | fn pause_unpause() { 98 | // The stream produced by `futures::stream::iter` is always ready. 99 | let mut stream = Pausable::new(futures::stream::iter(&[1, 2, 3, 4])); 100 | assert_eq!(Some(Some(&1)), stream.next().now_or_never()); 101 | assert_eq!(Some(Some(&2)), stream.next().now_or_never()); 102 | stream.pause(); 103 | assert_eq!(None, stream.next().now_or_never()); 104 | stream.unpause(); 105 | assert_eq!(Some(Some(&3)), stream.next().now_or_never()); 106 | assert_eq!(Some(Some(&4)), stream.next().now_or_never()); 107 | assert_eq!(Some(None), stream.next().now_or_never()) // end of stream 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /protocols/noise/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "libp2prs-noise" 3 | version = "0.4.0" 4 | license = "MIT" 5 | description = "Cryptographic handshake protocol using the noise framework." 6 | authors = ["Netwarps Technologies admin@paradeum.com"] 7 | repository = "https://github.com/netwarps/libp2p-rs" 8 | keywords = ["peer-to-peer", "libp2p", "networking"] 9 | categories = ["network-programming", "asynchronous"] 10 | edition = "2018" 11 | 12 | [dependencies] 13 | bytes = "0.5" 14 | curve25519-dalek = "2.0.0" 15 | futures = { version = "0.3", features = ["std"], default-features = false } 16 | lazy_static = "1.2" 17 | libp2prs-core = { path = "../../core", version = "0.4.0" } 18 | log = "0.4" 19 | prost = "0.6" 20 | rand = "0.8" 21 | sha2 = "0.8.0" 22 | static_assertions = "1" 23 | x25519-dalek = "1.1.0" 24 | zeroize = "1" 25 | async-trait = "0.1" 26 | pin-project = "1" 27 | 28 | [target.'cfg(not(target_arch = "wasm32"))'.dependencies] 29 | snow = { version = "0.8", features = ["ring-resolver"], default-features = false } 30 | 31 | [target.'cfg(target_arch = "wasm32")'.dependencies] 32 | snow = { version = "0.8", features = ["default-resolver"], default-features = false } 33 | 34 | [dev-dependencies] 35 | env_logger = "0.8" 36 | quickcheck = "0.9.0" 37 | sodiumoxide = "0.2.5" 38 | libp2prs-runtime = { path = "../../runtime", version = "0.4.0", features = ["async-std"] } 39 | libp2prs-tcp = { path = "../../transports/tcp", version = "0.4.0" } 40 | 41 | [build-dependencies] 42 | prost-build = "0.6" 43 | 44 | -------------------------------------------------------------------------------- /protocols/noise/build.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Parity Technologies (UK) Ltd. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a 4 | // copy of this software and associated documentation files (the "Software"), 5 | // to deal in the Software without restriction, including without limitation 6 | // the rights to use, copy, modify, merge, publish, distribute, sublicense, 7 | // and/or sell copies of the Software, and to permit persons to whom the 8 | // Software is furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 14 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 19 | // DEALINGS IN THE SOFTWARE. 20 | 21 | fn main() { 22 | prost_build::compile_protos(&["src/io/handshake/payload.proto"], &["src"]).unwrap(); 23 | } 24 | -------------------------------------------------------------------------------- /protocols/noise/src/error.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Parity Technologies (UK) Ltd. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a 4 | // copy of this software and associated documentation files (the "Software"), 5 | // to deal in the Software without restriction, including without limitation 6 | // the rights to use, copy, modify, merge, publish, distribute, sublicense, 7 | // and/or sell copies of the Software, and to permit persons to whom the 8 | // Software is furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 14 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 19 | // DEALINGS IN THE SOFTWARE. 20 | 21 | use libp2prs_core::{identity, transport::TransportError}; 22 | use snow::error::Error as SnowError; 23 | use std::{error::Error, fmt, io}; 24 | 25 | /// libp2p_noise error type. 26 | #[derive(Debug)] 27 | #[allow(clippy::manual_non_exhaustive)] 28 | pub enum NoiseError { 29 | /// An I/O error has been encountered. 30 | Io(io::Error), 31 | /// An noise framework error has been encountered. 32 | Noise(SnowError), 33 | /// A public key is invalid. 34 | InvalidKey, 35 | /// Authentication in a [`NoiseAuthenticated`](crate::NoiseAuthenticated) 36 | /// upgrade failed. 37 | AuthenticationFailed, 38 | /// A handshake payload is invalid. 39 | InvalidPayload(prost::DecodeError), 40 | /// A signature was required and could not be created. 41 | SigningError(identity::error::SigningError), 42 | #[doc(hidden)] 43 | __Nonexhaustive, 44 | } 45 | 46 | impl fmt::Display for NoiseError { 47 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 48 | match self { 49 | NoiseError::Io(e) => write!(f, "{}", e), 50 | NoiseError::Noise(e) => write!(f, "{}", e), 51 | NoiseError::InvalidKey => f.write_str("invalid public key"), 52 | NoiseError::InvalidPayload(e) => write!(f, "{}", e), 53 | NoiseError::AuthenticationFailed => f.write_str("Authentication failed"), 54 | NoiseError::SigningError(e) => write!(f, "{}", e), 55 | NoiseError::__Nonexhaustive => f.write_str("__Nonexhaustive"), 56 | } 57 | } 58 | } 59 | 60 | impl Error for NoiseError { 61 | fn source(&self) -> Option<&(dyn Error + 'static)> { 62 | match self { 63 | NoiseError::Io(e) => Some(e), 64 | NoiseError::Noise(_) => None, // TODO: `SnowError` should implement `Error`. 65 | NoiseError::InvalidKey => None, 66 | NoiseError::AuthenticationFailed => None, 67 | NoiseError::InvalidPayload(e) => Some(e), 68 | NoiseError::SigningError(e) => Some(e), 69 | NoiseError::__Nonexhaustive => None, 70 | } 71 | } 72 | } 73 | 74 | impl From for NoiseError { 75 | fn from(e: io::Error) -> Self { 76 | NoiseError::Io(e) 77 | } 78 | } 79 | 80 | impl From for NoiseError { 81 | fn from(e: SnowError) -> Self { 82 | NoiseError::Noise(e) 83 | } 84 | } 85 | 86 | impl From for NoiseError { 87 | fn from(e: prost::DecodeError) -> Self { 88 | NoiseError::InvalidPayload(e) 89 | } 90 | } 91 | 92 | impl From for NoiseError { 93 | fn from(e: identity::error::SigningError) -> Self { 94 | NoiseError::SigningError(e) 95 | } 96 | } 97 | 98 | impl From for TransportError { 99 | fn from(_: NoiseError) -> Self { 100 | // TODO: make a security error catalog for noise 101 | TransportError::Internal 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /protocols/noise/src/io/handshake/payload.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package payload.proto; 4 | 5 | // Payloads for Noise handshake messages. 6 | 7 | message NoiseHandshakePayload { 8 | bytes identity_key = 1; 9 | bytes identity_sig = 2; 10 | bytes data = 3; 11 | } 12 | -------------------------------------------------------------------------------- /protocols/plaintext/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "libp2prs-plaintext" 3 | version = "0.4.0" 4 | license = "MIT" 5 | description = "Plaintext encryption dummy protocol for libp2p " 6 | authors = ["Netwarps Technologies admin@paradeum.com"] 7 | repository = "https://github.com/netwarps/libp2p-rs" 8 | keywords = ["peer-to-peer", "libp2p", "networking"] 9 | categories = ["network-programming", "asynchronous"] 10 | edition = "2018" 11 | 12 | [dependencies] 13 | libp2prs-core = { path = "../../core", version = "0.4.0" } 14 | bytes = "0.5" 15 | futures = { version = "0.3", features = ["std"], default-features = false } 16 | log = "0.4" 17 | async-trait = "0.1" 18 | prost = "0.6" 19 | pin-project = "1" 20 | 21 | 22 | [dev-dependencies] 23 | env_logger = "0.8" 24 | libp2prs-runtime = { path = "../../runtime", version = "0.4.0", features = ["async-std"] } 25 | 26 | [build-dependencies] 27 | prost-build = "0.6" -------------------------------------------------------------------------------- /protocols/plaintext/build.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Netwarps Ltd. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a 4 | // copy of this software and associated documentation files (the "Software"), 5 | // to deal in the Software without restriction, including without limitation 6 | // the rights to use, copy, modify, merge, publish, distribute, sublicense, 7 | // and/or sell copies of the Software, and to permit persons to whom the 8 | // Software is furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 14 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 19 | // DEALINGS IN THE SOFTWARE. 20 | 21 | fn main() { 22 | prost_build::compile_protos(&["src/handshake/structs.proto"], &["src/handshake"]).unwrap(); 23 | } 24 | -------------------------------------------------------------------------------- /protocols/plaintext/examples/plaintext_simple.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Netwarps Ltd. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a 4 | // copy of this software and associated documentation files (the "Software"), 5 | // to deal in the Software without restriction, including without limitation 6 | // the rights to use, copy, modify, merge, publish, distribute, sublicense, 7 | // and/or sell copies of the Software, and to permit persons to whom the 8 | // Software is furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 14 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 19 | // DEALINGS IN THE SOFTWARE. 20 | 21 | use libp2prs_core::identity::Keypair; 22 | use libp2prs_runtime::{ 23 | net::{TcpListener, TcpStream}, 24 | task, 25 | }; 26 | use log::{info, LevelFilter}; 27 | 28 | use futures::{AsyncReadExt, AsyncWriteExt}; 29 | use libp2prs_plaintext::PlainTextConfig; 30 | 31 | fn main() { 32 | env_logger::builder().filter_level(LevelFilter::Info).init(); 33 | 34 | if std::env::args().nth(1) == Some("server".to_string()) { 35 | info!("Starting server ......"); 36 | server(); 37 | } else { 38 | info!("Starting client ......"); 39 | client(); 40 | } 41 | } 42 | 43 | fn server() { 44 | let key = Keypair::generate_secp256k1(); 45 | let config = PlainTextConfig::new(key); 46 | 47 | task::block_on(async move { 48 | let listener = TcpListener::bind("127.0.0.1:1337").await.unwrap(); 49 | 50 | while let Ok((socket, _)) = listener.accept().await { 51 | let config = config.clone(); 52 | task::spawn(async move { 53 | let (mut handle, _) = config.handshake(socket).await.unwrap(); 54 | 55 | info!("session started!"); 56 | 57 | let mut buf = [0u8; 100]; 58 | 59 | while let Ok(n) = handle.read(&mut buf).await { 60 | buf[11] = b"!"[0]; 61 | if handle.write_all(&buf[..n + 1]).await.is_err() { 62 | break; 63 | } 64 | } 65 | 66 | info!("session closed!"); 67 | let _ = handle.close().await; 68 | }); 69 | } 70 | }); 71 | } 72 | 73 | fn client() { 74 | let key = Keypair::generate_secp256k1(); 75 | let config = PlainTextConfig::new(key); 76 | 77 | let data = b"hello world"; 78 | 79 | task::block_on(async move { 80 | let stream = TcpStream::connect("127.0.0.1:1337").await.unwrap(); 81 | let (mut handle, _) = config.handshake(stream).await.unwrap(); 82 | match handle.write_all(data.as_ref()).await { 83 | Ok(_) => info!("send all"), 84 | Err(e) => info!("err: {:?}", e), 85 | } 86 | 87 | let mut buf = [0; 100]; 88 | let n = handle.read(&mut buf).await.unwrap(); 89 | info!("receive: {:?}", &buf[..n]); 90 | }); 91 | } 92 | -------------------------------------------------------------------------------- /protocols/plaintext/src/handshake/mod.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Netwarps Ltd. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a 4 | // copy of this software and associated documentation files (the "Software"), 5 | // to deal in the Software without restriction, including without limitation 6 | // the rights to use, copy, modify, merge, publish, distribute, sublicense, 7 | // and/or sell copies of the Software, and to permit persons to whom the 8 | // Software is furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 14 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 19 | // DEALINGS IN THE SOFTWARE. 20 | 21 | pub(crate) mod handshake_plaintext; 22 | -------------------------------------------------------------------------------- /protocols/plaintext/src/handshake/structs.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto2"; 2 | 3 | package structs_proto; 4 | 5 | message Exchange { 6 | optional bytes id = 1; 7 | optional bytes pubkey = 2; 8 | } 9 | -------------------------------------------------------------------------------- /protocols/secio/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "libp2prs-secio" 3 | version = "0.4.0" 4 | license = "MIT" 5 | description = "Secio encryption protocol for libp2p" 6 | authors = ["Netwarps Technologies admin@paradeum.com"] 7 | repository = "https://github.com/netwarps/libp2p-rs" 8 | keywords = ["peer-to-peer", "libp2p", "networking"] 9 | categories = ["network-programming", "asynchronous"] 10 | edition = "2018" 11 | 12 | [dependencies] 13 | libp2prs-core = { path = "../../core", version = "0.4.0" } 14 | bytes = "0.5" 15 | futures = { version = "0.3", features = ["std"], default-features = false } 16 | log = "0.4" 17 | async-trait = "0.1" 18 | quicksink = "0.1" 19 | pin-project = "1" 20 | secp256k1 = "0.20" 21 | rand = "0.7" 22 | ring = "0.16.5" 23 | unsigned-varint = "0.4" 24 | bs58 = "0.4.0" 25 | prost = "0.6" 26 | aes = { version = "0.7.0", features = ["ctr", "force-soft"] } 27 | stream-cipher = "0.4.1" 28 | 29 | [build-dependencies] 30 | prost-build = "0.6.1" 31 | 32 | [dev-dependencies] 33 | env_logger = "0.8" 34 | criterion = "0.3" 35 | libp2prs-runtime = { path = "../../runtime", version = "0.4.0", features = ["async-std"] } 36 | 37 | [[bench]] 38 | name = "bench" 39 | harness = false 40 | -------------------------------------------------------------------------------- /protocols/secio/build.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Netwarps Ltd. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a 4 | // copy of this software and associated documentation files (the "Software"), 5 | // to deal in the Software without restriction, including without limitation 6 | // the rights to use, copy, modify, merge, publish, distribute, sublicense, 7 | // and/or sell copies of the Software, and to permit persons to whom the 8 | // Software is furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 14 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 19 | // DEALINGS IN THE SOFTWARE. 20 | 21 | use std::env; 22 | 23 | #[allow(clippy::inconsistent_digit_grouping)] 24 | fn main() { 25 | if let Ok(v) = env::var("DEP_OPENSSL_VERSION_NUMBER") { 26 | let version = u64::from_str_radix(&v, 16).unwrap(); 27 | 28 | if version >= 0x1010_0000 { 29 | println!("cargo:rustc-cfg=ossl110"); 30 | } 31 | } 32 | prost_build::compile_protos(&["src/crypto/keys.proto"], &["src/crypto"]).unwrap(); 33 | prost_build::compile_protos(&["src/handshake/structs.proto"], &["src/handshake"]).unwrap(); 34 | } 35 | -------------------------------------------------------------------------------- /protocols/secio/examples/go/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM golang:1.14-alpine as builder 2 | WORKDIR /usr/src/app 3 | COPY ./go.mod ./ 4 | COPY ./go.sum ./ 5 | RUN go mod download 6 | COPY . . 7 | RUN CGO_ENABLED=0 GOARCH=amd64 GOOS=linux go build -ldflags "-s -w" -o go-secio-server 8 | 9 | FROM scratch as runner 10 | LABEL maintainer "kuang" 11 | COPY --from=builder /usr/src/app/go-secio-server /opt/app/ 12 | EXPOSE 1337 13 | CMD ["/opt/app/go-secio-server"] 14 | 15 | -------------------------------------------------------------------------------- /protocols/secio/examples/go/go.mod: -------------------------------------------------------------------------------- 1 | module go-secio-examples 2 | 3 | require ( 4 | github.com/gogo/protobuf v1.3.1 5 | github.com/google/uuid v1.1.1 6 | github.com/ipfs/go-datastore v0.4.2 7 | github.com/ipfs/go-log v0.0.1 8 | github.com/libp2p/go-libp2p v0.5.2 9 | github.com/libp2p/go-libp2p-autonat-svc v0.1.0 10 | github.com/libp2p/go-libp2p-circuit v0.1.4 11 | github.com/libp2p/go-libp2p-connmgr v0.2.1 12 | github.com/libp2p/go-libp2p-core v0.3.0 13 | github.com/libp2p/go-libp2p-discovery v0.2.0 14 | github.com/libp2p/go-libp2p-kad-dht v0.5.0 15 | github.com/libp2p/go-libp2p-quic-transport v0.2.3 16 | github.com/libp2p/go-libp2p-routing v0.1.0 17 | github.com/libp2p/go-libp2p-secio v0.2.2 18 | github.com/libp2p/go-libp2p-swarm v0.2.2 19 | github.com/libp2p/go-libp2p-testing v0.1.1 20 | github.com/libp2p/go-libp2p-tls v0.1.3 21 | github.com/minio/sha256-simd v0.1.1 22 | github.com/multiformats/go-multiaddr v0.2.0 23 | github.com/multiformats/go-multiaddr-net v0.1.2 24 | github.com/whyrusleeping/go-logging v0.0.1 25 | ) 26 | 27 | go 1.13 28 | -------------------------------------------------------------------------------- /protocols/secio/examples/go/server.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Netwarps Ltd. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a 4 | // copy of this software and associated documentation files (the "Software"), 5 | // to deal in the Software without restriction, including without limitation 6 | // the rights to use, copy, modify, merge, publish, distribute, sublicense, 7 | // and/or sell copies of the Software, and to permit persons to whom the 8 | // Software is furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 14 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 19 | // DEALINGS IN THE SOFTWARE. 20 | 21 | package main 22 | 23 | import ( 24 | "fmt" 25 | "net" 26 | "context" 27 | "io" 28 | ci "github.com/libp2p/go-libp2p-core/crypto" 29 | "github.com/libp2p/go-libp2p-core/peer" 30 | "github.com/libp2p/go-libp2p-core/sec" 31 | secio "github.com/libp2p/go-libp2p-secio" 32 | ) 33 | 34 | 35 | 36 | func main() { 37 | serverTpt := newTransport(ci.Secp256k1, 32) 38 | lstnr, err := net.Listen("tcp", "0.0.0.0:1337") 39 | if err != nil { 40 | panic(err) 41 | } 42 | for { 43 | server, err := lstnr.Accept() 44 | if err != nil { 45 | panic(err) 46 | } 47 | serverConn, err := serverTpt.SecureInbound(context.TODO(), server) 48 | fmt.Println("local id",serverTpt.LocalID) 49 | if err != nil { 50 | panic(err) 51 | } 52 | go handleClient(serverConn) 53 | } 54 | } 55 | 56 | type keyInfo struct { 57 | cipherKey []byte 58 | iv []byte 59 | macKey []byte 60 | } 61 | 62 | 63 | 64 | 65 | func handleClient(conn sec.SecureConn) { 66 | defer conn.Close() 67 | buf := make([]byte, 256) // using small tmo buffer for demonstrating 68 | for { 69 | n, err := conn.Read(buf) 70 | if err != nil { 71 | if err != io.EOF { 72 | fmt.Println("read error:", err) 73 | } 74 | break 75 | } 76 | fmt.Println("got", n, "bytes.") 77 | fmt.Println("buf:", buf) 78 | fmt.Println("rev msg:", string(buf[:n])) 79 | conn.Write(buf[:n]) 80 | 81 | } 82 | } 83 | 84 | func newTransport(typ, bits int) *secio.Transport { 85 | priv, pub, err := ci.GenerateKeyPair(typ, bits) 86 | fmt.Println("priv",priv) 87 | if err != nil { 88 | panic(err) 89 | } 90 | id, err := peer.IDFromPublicKey(pub) 91 | if err != nil { 92 | panic(err) 93 | } 94 | return &secio.Transport{ 95 | PrivateKey: priv, 96 | LocalID: id, 97 | } 98 | } 99 | 100 | -------------------------------------------------------------------------------- /protocols/secio/examples/secio_simple.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Netwarps Ltd. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a 4 | // copy of this software and associated documentation files (the "Software"), 5 | // to deal in the Software without restriction, including without limitation 6 | // the rights to use, copy, modify, merge, publish, distribute, sublicense, 7 | // and/or sell copies of the Software, and to permit persons to whom the 8 | // Software is furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 14 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 19 | // DEALINGS IN THE SOFTWARE. 20 | 21 | use libp2prs_core::identity::Keypair; 22 | use libp2prs_runtime::{net, task}; 23 | use libp2prs_secio::Config; 24 | use log::info; 25 | 26 | // use libp2prs_traits::{ReadEx, WriteEx}; 27 | use futures::{AsyncReadExt, AsyncWriteExt}; 28 | 29 | fn main() { 30 | env_logger::init(); 31 | 32 | if std::env::args().nth(1) == Some("server".to_string()) { 33 | info!("Starting server ......"); 34 | server(); 35 | } else { 36 | info!("Starting client ......"); 37 | client(); 38 | } 39 | } 40 | 41 | fn server() { 42 | let key = Keypair::generate_secp256k1(); 43 | let config = Config::new(key); 44 | 45 | task::block_on(async move { 46 | let listener = net::TcpListener::bind("127.0.0.1:1337").await.unwrap(); 47 | 48 | while let Ok((socket, _)) = listener.accept().await { 49 | let config = config.clone(); 50 | task::spawn(async move { 51 | let (mut handle, _, _) = config.handshake(socket).await.unwrap(); 52 | 53 | info!("session started!"); 54 | 55 | let mut buf = [0; 100]; 56 | 57 | while let Ok(n) = handle.read(&mut buf).await { 58 | if n == 0 { 59 | break; 60 | } 61 | if handle.write_all(&buf[..n]).await.is_err() { 62 | break; 63 | } 64 | handle.flush().await.expect("expect handle flush"); 65 | } 66 | 67 | info!("session closed!"); 68 | let _ = handle.close().await; 69 | 70 | // let (h1, h2) = handle.split(); 71 | // match async_std::io::copy(h1, h2).await { 72 | // Ok(n) => { 73 | // error!("io-copy exited @len={}", n); 74 | // } 75 | // Err(err) => { 76 | // error!("io-copy exited @{:?}", err); 77 | // } 78 | // } 79 | }); 80 | } 81 | }); 82 | } 83 | 84 | fn client() { 85 | let key = Keypair::generate_secp256k1(); 86 | let config = Config::new(key); 87 | 88 | let data = b"hello world"; 89 | 90 | task::block_on(async move { 91 | let stream = net::TcpStream::connect("127.0.0.1:1337").await.unwrap(); 92 | let (mut handle, _, _) = config.handshake(stream).await.unwrap(); 93 | match handle.write_all(data.as_ref()).await { 94 | Ok(_) => info!("send all"), 95 | Err(e) => info!("err: {:?}", e), 96 | } 97 | handle.flush().await.expect("expect handle flush"); 98 | 99 | let mut buf = [0; 100]; 100 | let n = handle.read(&mut buf).await.unwrap(); 101 | info!("receive: {:?}", &buf[..n]); 102 | }); 103 | } 104 | -------------------------------------------------------------------------------- /protocols/secio/src/codec/mod.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2017 Parity Technologies (UK) Ltd. 2 | // Copyright 2020 Netwarps Ltd. 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a 5 | // copy of this software and associated documentation files (the "Software"), 6 | // to deal in the Software without restriction, including without limitation 7 | // the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 | // and/or sell copies of the Software, and to permit persons to whom the 9 | // Software is furnished to do so, subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 15 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 20 | // DEALINGS IN THE SOFTWARE. 21 | 22 | /// Hmac struct on this module comes from `rust-libp2p`, but use high version of hamc 23 | 24 | /// Encryption and decryption stream 25 | pub mod secure_stream; 26 | 27 | use crate::Digest; 28 | 29 | /// Hash-based Message Authentication Code (HMAC). 30 | #[derive(Debug, Clone)] 31 | pub struct Hmac(ring::hmac::Key); 32 | 33 | impl Hmac { 34 | /// Returns the size of the hash in bytes. 35 | #[inline] 36 | pub fn num_bytes(&self) -> usize { 37 | self.0.algorithm().digest_algorithm().output_len 38 | } 39 | 40 | /// Builds a `Hmac` from an algorithm and key. 41 | pub fn from_key(algorithm: Digest, key: &[u8]) -> Self { 42 | match algorithm { 43 | Digest::Sha256 => Hmac(ring::hmac::Key::new(ring::hmac::HMAC_SHA256, key)), 44 | Digest::Sha512 => Hmac(ring::hmac::Key::new(ring::hmac::HMAC_SHA512, key)), 45 | } 46 | } 47 | 48 | /// Signs the data. 49 | pub fn sign(&mut self, crypted_data: &[u8]) -> ring::hmac::Tag { 50 | ring::hmac::sign(&self.0, crypted_data) 51 | } 52 | 53 | /// Verifies that the data matches the expected hash. 54 | pub fn verify(&mut self, crypted_data: &[u8], expected_hash: &[u8]) -> bool { 55 | ring::hmac::verify(&self.0, crypted_data, expected_hash).is_ok() 56 | } 57 | 58 | /// Return a multi-step hmac context 59 | pub fn context(&self) -> ring::hmac::Context { 60 | ring::hmac::Context::with_key(&self.0) 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /protocols/secio/src/crypto/cipher.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Parity Technologies (UK) Ltd. 2 | // Copyright 2020 Netwarps Ltd. 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a 5 | // copy of this software and associated documentation files (the "Software"), 6 | // to deal in the Software without restriction, including without limitation 7 | // the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 | // and/or sell copies of the Software, and to permit persons to whom the 9 | // Software is furnished to do so, subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 15 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 20 | // DEALINGS IN THE SOFTWARE. 21 | 22 | use crate::crypto::ctr_impl::CTR128LEN; 23 | use ring::aead; 24 | 25 | /// Possible encryption ciphers. 26 | #[derive(Clone, Copy, Debug, Eq, PartialEq)] 27 | pub enum CipherType { 28 | /// Aes128Ctr 29 | Aes128Ctr, 30 | /// Aes128Gcm 31 | Aes128Gcm, 32 | /// Aes256Gcm 33 | Aes256Gcm, 34 | /// ChaCha20Poly1305 35 | ChaCha20Poly1305, 36 | } 37 | 38 | impl CipherType { 39 | /// Returns the size of in bytes of the key expected by the cipher. 40 | pub fn key_size(self) -> usize { 41 | match self { 42 | CipherType::Aes128Ctr => CTR128LEN, 43 | CipherType::Aes128Gcm => aead::AES_128_GCM.key_len(), 44 | CipherType::Aes256Gcm => aead::AES_256_GCM.key_len(), 45 | CipherType::ChaCha20Poly1305 => aead::CHACHA20_POLY1305.key_len(), 46 | } 47 | } 48 | 49 | /// Returns the size of in bytes of the IV expected by the cipher. 50 | #[inline] 51 | pub fn iv_size(self) -> usize { 52 | match self { 53 | CipherType::Aes128Ctr => CTR128LEN, 54 | CipherType::Aes128Gcm => aead::AES_128_GCM.nonce_len(), 55 | CipherType::Aes256Gcm => aead::AES_256_GCM.nonce_len(), 56 | CipherType::ChaCha20Poly1305 => aead::CHACHA20_POLY1305.nonce_len(), 57 | } 58 | } 59 | 60 | /// Returns the size of in bytes of the tag expected by the cipher. 61 | #[inline] 62 | pub fn tag_size(self) -> usize { 63 | match self { 64 | CipherType::Aes128Ctr => 0, 65 | CipherType::Aes128Gcm => aead::AES_128_GCM.tag_len(), 66 | CipherType::Aes256Gcm => aead::AES_256_GCM.tag_len(), 67 | CipherType::ChaCha20Poly1305 => aead::CHACHA20_POLY1305.tag_len(), 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /protocols/secio/src/crypto/ctr_impl.rs: -------------------------------------------------------------------------------- 1 | use crate::crypto::StreamCipher as Crypto_StreamCipher; 2 | use crate::error::SecioError; 3 | 4 | use aes::cipher::generic_array::GenericArray; 5 | use aes::cipher::{FromBlockCipher, NewBlockCipher, StreamCipher}; 6 | use aes::{Aes128, Aes128Ctr}; 7 | 8 | pub static CTR128LEN: usize = 16; 9 | 10 | pub(crate) struct CTRCipher { 11 | cipher: Aes128Ctr, 12 | } 13 | 14 | impl CTRCipher { 15 | /// Create a CTRCipher 16 | pub fn new(key: &[u8], iv: &[u8]) -> Self { 17 | let iv = GenericArray::from_slice(iv); 18 | let aes_128 = Aes128::new(GenericArray::from_slice(key)); 19 | let cipher = Aes128Ctr::from_block_cipher(aes_128, iv); 20 | CTRCipher { cipher } 21 | } 22 | 23 | /// Encrypt `input` to `temp`, tag.len() in ctr mode is zero. 24 | pub fn encrypt(&mut self, input: &[u8]) -> Result, SecioError> { 25 | let mut output = Vec::from(input); 26 | self.cipher.apply_keystream(&mut output); 27 | Ok(output) 28 | } 29 | 30 | /// Decrypt `input` to `output`, tag.len() in ctr mode is zero. 31 | pub fn decrypt(&mut self, input: &[u8]) -> Result, SecioError> { 32 | let mut output = Vec::from(input); 33 | self.cipher.apply_keystream(&mut output); 34 | Ok(output) 35 | } 36 | } 37 | 38 | impl Crypto_StreamCipher for CTRCipher { 39 | fn encrypt(&mut self, input: &[u8]) -> Result, SecioError> { 40 | self.encrypt(input) 41 | } 42 | 43 | fn decrypt(&mut self, input: &[u8]) -> Result, SecioError> { 44 | self.decrypt(input) 45 | } 46 | } 47 | 48 | #[cfg(test)] 49 | mod test { 50 | use crate::crypto::cipher::CipherType; 51 | use crate::crypto::ctr_impl::CTRCipher; 52 | 53 | fn test_ctr(mode: CipherType) { 54 | let key = (0..mode.key_size()).map(|_| rand::random::()).collect::>(); 55 | let iv = (0..mode.iv_size()).map(|_| rand::random::()).collect::>(); 56 | 57 | let mut encryptor = CTRCipher::new(key.as_ref(), iv.as_ref()); 58 | let mut decryptor = CTRCipher::new(key.as_ref(), iv.as_ref()); 59 | 60 | let message = b"HELLO WORLD"; 61 | let encrypted_msg = encryptor.encrypt(message).unwrap(); 62 | let decrypted_msg = decryptor.decrypt(&encrypted_msg[..]).unwrap(); 63 | assert_eq!(&decrypted_msg[..], message); 64 | 65 | let message = b"hello world"; 66 | let encrypted_msg = encryptor.encrypt(message).unwrap(); 67 | let decrypted_msg = decryptor.decrypt(&encrypted_msg[..]).unwrap(); 68 | assert_eq!(&decrypted_msg[..], message); 69 | } 70 | 71 | #[test] 72 | fn test_aes_128_ctr() { 73 | test_ctr(CipherType::Aes128Ctr); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /protocols/secio/src/crypto/keys.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto2"; 2 | 3 | package keys_proto; 4 | 5 | enum KeyType { 6 | RSA = 0; 7 | Ed25519 = 1; 8 | Secp256k1 = 2; 9 | } 10 | 11 | message PublicKey { 12 | required KeyType Type = 1; 13 | required bytes Data = 2; 14 | } 15 | 16 | message PrivateKey { 17 | required KeyType Type = 1; 18 | required bytes Data = 2; 19 | } 20 | -------------------------------------------------------------------------------- /protocols/secio/src/crypto/mod.rs: -------------------------------------------------------------------------------- 1 | use crate::error::SecioError; 2 | 3 | /// Define cipher 4 | pub mod cipher; 5 | 6 | mod ring_impl; 7 | 8 | mod ctr_impl; 9 | 10 | /// Variant cipher which contains all possible stream ciphers 11 | #[doc(hidden)] 12 | pub type BoxStreamCipher = Box; 13 | 14 | /// Basic operation of Cipher, which is a Symmetric Cipher. 15 | #[doc(hidden)] 16 | pub trait StreamCipher { 17 | /// Feeds data from input through the cipher, return encrypted bytes. 18 | fn encrypt(&mut self, input: &[u8]) -> Result, SecioError>; 19 | /// Feeds data from input through the cipher, return decrypted bytes. 20 | fn decrypt(&mut self, input: &[u8]) -> Result, SecioError>; 21 | } 22 | 23 | /// Crypto mode, encrypt or decrypt 24 | #[derive(Clone, Copy, Eq, PartialEq, Debug)] 25 | #[doc(hidden)] 26 | pub enum CryptoMode { 27 | /// Encrypt 28 | Encrypt, 29 | /// Decrypt 30 | Decrypt, 31 | } 32 | 33 | /// Generate a specific Cipher with key and initialize vector 34 | #[doc(hidden)] 35 | pub fn new_stream(t: cipher::CipherType, key: &[u8], iv: &[u8], mode: CryptoMode) -> BoxStreamCipher { 36 | match t { 37 | cipher::CipherType::Aes128Ctr => Box::new(ctr_impl::CTRCipher::new(key, iv)), 38 | cipher::CipherType::Aes128Gcm | cipher::CipherType::Aes256Gcm | cipher::CipherType::ChaCha20Poly1305 => { 39 | Box::new(ring_impl::RingAeadCipher::new(t, key, mode)) 40 | } 41 | } 42 | } 43 | 44 | /// [0, 0, 0, 0] 45 | /// [1, 0, 0, 0] 46 | /// ... 47 | /// [255, 0, 0, 0] 48 | /// [0, 1, 0, 0] 49 | /// [1, 1, 0, 0] 50 | /// ... 51 | fn nonce_advance(nonce: &mut [u8]) { 52 | for i in nonce { 53 | if std::u8::MAX == *i { 54 | *i = 0; 55 | } else { 56 | *i += 1; 57 | return; 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /protocols/secio/src/exchange.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Parity Technologies (UK) Ltd. 2 | // Copyright 2020 Netwarps Ltd. 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a 5 | // copy of this software and associated documentation files (the "Software"), 6 | // to deal in the Software without restriction, including without limitation 7 | // the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 | // and/or sell copies of the Software, and to permit persons to whom the 9 | // Software is furnished to do so, subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 15 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 20 | // DEALINGS IN THE SOFTWARE. 21 | 22 | /// Most of the code for this module comes from `rust-libp2p`. 23 | /// Change return type to Result 24 | use log::debug; 25 | use ring::agreement; 26 | use ring::rand as ring_rand; 27 | 28 | use crate::error::SecioError; 29 | 30 | /// Possible key agreement algorithms. 31 | #[derive(Copy, Clone, Debug, PartialEq, Eq)] 32 | pub enum KeyAgreement { 33 | EcdhP256, 34 | EcdhP384, 35 | } 36 | 37 | #[allow(clippy::from_over_into)] 38 | impl Into<&'static agreement::Algorithm> for KeyAgreement { 39 | #[inline] 40 | fn into(self) -> &'static agreement::Algorithm { 41 | match self { 42 | KeyAgreement::EcdhP256 => &agreement::ECDH_P256, 43 | KeyAgreement::EcdhP384 => &agreement::ECDH_P384, 44 | } 45 | } 46 | } 47 | 48 | /// Generates a new key pair as part of the exchange. 49 | /// 50 | /// Returns the opaque private key and the corresponding public key. 51 | pub fn generate_agreement(algorithm: KeyAgreement) -> Result<(agreement::EphemeralPrivateKey, Vec), SecioError> { 52 | let rng = ring_rand::SystemRandom::new(); 53 | 54 | match agreement::EphemeralPrivateKey::generate(algorithm.into(), &rng) { 55 | Ok(tmp_priv_key) => { 56 | let tmp_pub_key = tmp_priv_key 57 | .compute_public_key() 58 | .map_err(|_| SecioError::EphemeralKeyGenerationFailed)?; 59 | Ok((tmp_priv_key, tmp_pub_key.as_ref().to_vec())) 60 | } 61 | Err(_) => { 62 | debug!("failed to generate ECDH key"); 63 | Err(SecioError::EphemeralKeyGenerationFailed) 64 | } 65 | } 66 | } 67 | 68 | /// Finish the agreement. On success, returns the shared key that both remote agreed upon. 69 | pub fn agree( 70 | algorithm: KeyAgreement, 71 | my_private_key: agreement::EphemeralPrivateKey, 72 | other_public_key: &[u8], 73 | ) -> Result, SecioError> { 74 | agreement::agree_ephemeral( 75 | my_private_key, 76 | &agreement::UnparsedPublicKey::new(algorithm.into(), other_public_key), 77 | SecioError::SecretGenerationFailed, 78 | |key_material| Ok(key_material.to_vec()), 79 | ) 80 | } 81 | -------------------------------------------------------------------------------- /protocols/secio/src/handshake/mod.rs: -------------------------------------------------------------------------------- 1 | /// Most of the code for this module comes from `rust-libp2p`, but modified some logic(struct). 2 | mod handshake_context; 3 | pub(crate) mod procedure; 4 | -------------------------------------------------------------------------------- /protocols/secio/src/handshake/structs.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto2"; 2 | 3 | package handshake_proto; 4 | 5 | message Propose { 6 | required bytes rand = 1; 7 | required bytes pubkey = 2; 8 | required string exchanges = 3; 9 | required string ciphers = 4; 10 | required string hashes = 5; 11 | } 12 | 13 | message Exchange { 14 | required bytes epubkey = 1; 15 | required bytes signature = 2; 16 | } -------------------------------------------------------------------------------- /protocols/yamux/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "libp2prs-yamux" 3 | version = "0.4.0" 4 | license = "MIT" 5 | description = "Yamux multiplexing protocol for libp2p" 6 | authors = ["Netwarps Technologies admin@paradeum.com"] 7 | repository = "https://github.com/netwarps/libp2p-rs" 8 | keywords = ["peer-to-peer", "libp2p", "networking"] 9 | categories = ["network-programming", "asynchronous"] 10 | edition = "2018" 11 | 12 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 13 | [dependencies] 14 | libp2prs-core = { path = "../../core", version = "0.4.0" } 15 | async-trait = "0.1" 16 | futures = { version = "0.3", features = ["std"], default-features = false } 17 | log = "0.4" 18 | yamux = "0.9.0" 19 | parking_lot = "0.11" 20 | pin-project = "1" 21 | 22 | [dev-dependencies] 23 | env_logger = "0.8" 24 | criterion = "0.3" 25 | quickcheck = "0.9" 26 | libp2prs-runtime = { path = "../../runtime", version = "0.4.0", features = ["async-std"] } 27 | libp2prs-tcp = { path = "../../transports/tcp", version = "0.4.0" } 28 | libp2prs-secio = { path = "../../protocols/secio", version = "0.4.0" } 29 | -------------------------------------------------------------------------------- /runtime/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "libp2prs-runtime" 3 | version = "0.4.0" 4 | license = "MIT" 5 | description = "runtime which support async-std and tokio" 6 | authors = ["Netwarps Technologies admin@paradeum.com"] 7 | repository = "https://github.com/netwarps/libp2p-rs" 8 | keywords = ["peer-to-peer", "libp2p", "networking", "task"] 9 | categories = ["network-programming", "asynchronous"] 10 | edition = "2018" 11 | 12 | [dependencies] 13 | log = "0.4" 14 | futures = { version = "0.3", features = ["std", "executor"], default-features = false } 15 | once_cell = "1.5" 16 | 17 | async-std = { version = "1.8", optional = true, features = ["default"] } 18 | tokio = { version = "1.0", optional = true, features = ["rt-multi-thread", "net", "time"] } 19 | 20 | 21 | [dev-dependencies] 22 | env_logger = "0.8" 23 | -------------------------------------------------------------------------------- /runtime/README.md: -------------------------------------------------------------------------------- 1 | 2 | ### A simple wrapper for async-std and tokio runtimes. -------------------------------------------------------------------------------- /runtime/examples/task_simple.rs: -------------------------------------------------------------------------------- 1 | use libp2prs_runtime::task; 2 | use std::time::Duration; 3 | 4 | fn main() { 5 | task::block_on(async { 6 | //let s = TcpStream::connect(); 7 | 8 | let h = task::spawn(async { 9 | { 10 | task::sleep(Duration::from_secs(1)).await; 11 | } 12 | 13 | 32 14 | }); 15 | 16 | let a = h.wait().await; 17 | println!("forced closed {:?}", a); 18 | 19 | task::sleep(Duration::from_millis(1200)).await; 20 | 21 | println!("wait for exit "); 22 | 23 | // let a = h.terminate().await; 24 | // println!("forced closed {:?}", a); 25 | 26 | //h.await; 27 | 28 | //let b = h.cancel().await; 29 | std::thread::sleep(Duration::from_millis(1000)); 30 | 31 | println!("exited"); 32 | }); 33 | 34 | std::thread::sleep(Duration::from_millis(1000)); 35 | } 36 | -------------------------------------------------------------------------------- /runtime/src/async_std/mod.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Netwarps Ltd. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a 4 | // copy of this software and associated documentation files (the "Software"), 5 | // to deal in the Software without restriction, including without limitation 6 | // the rights to use, copy, modify, merge, publish, distribute, sublicense, 7 | // and/or sell copies of the Software, and to permit persons to whom the 8 | // Software is furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 14 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 19 | // DEALINGS IN THE SOFTWARE. 20 | 21 | pub mod net; 22 | pub mod task; 23 | -------------------------------------------------------------------------------- /runtime/src/async_std/task.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Netwarps Ltd. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a 4 | // copy of this software and associated documentation files (the "Software"), 5 | // to deal in the Software without restriction, including without limitation 6 | // the rights to use, copy, modify, merge, publish, distribute, sublicense, 7 | // and/or sell copies of the Software, and to permit persons to whom the 8 | // Software is furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 14 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 19 | // DEALINGS IN THE SOFTWARE. 20 | 21 | use futures::FutureExt; 22 | use std::future::Future; 23 | use std::pin::Pin; 24 | use std::task::{Context, Poll}; 25 | use std::time::Duration; 26 | 27 | use async_std::future; 28 | use async_std::task; 29 | use async_std::task::JoinHandle; 30 | 31 | #[derive(Debug)] 32 | pub struct TaskHandle(JoinHandle); 33 | 34 | impl TaskHandle { 35 | /// Cancels the runtime immediately, then awaits it. The cancelled runtime might complete 36 | /// normally with `Some()` or most likely it returns `None`. 37 | pub async fn cancel(self) -> Option { 38 | self.0.cancel().await 39 | } 40 | 41 | /// Waits for the runtime to complete. The runtime will complete normally with `Some()` in 42 | /// most cases, or it returns `None` if it gets cancelled for some reason. 43 | /// 44 | /// This method is actually the Future implemented by itself. 45 | pub async fn wait(self) -> Option { 46 | self.await 47 | } 48 | } 49 | 50 | impl Future for TaskHandle { 51 | type Output = Option; 52 | 53 | fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { 54 | self.0.poll_unpin(cx).map(Some) 55 | } 56 | } 57 | 58 | /// Spawns a runtime and blocks the current thread on its result. 59 | pub fn block_on(future: F) -> T 60 | where 61 | F: Future, 62 | { 63 | task::block_on(future) 64 | } 65 | 66 | /// Spawns a runtime. 67 | /// 68 | /// The returned TaskHandle can be used to terminate and wait for its termination. 69 | /// 70 | /// Note: the output of the future must be (). 71 | pub fn spawn(future: F) -> TaskHandle 72 | where 73 | F: Future + Send + 'static, 74 | T: Send + 'static, 75 | { 76 | let h = task::spawn(async move { future.await }); 77 | TaskHandle(h) 78 | } 79 | 80 | /// Sleeps for the specified amount of time. 81 | pub async fn sleep(dur: Duration) { 82 | task::sleep(dur).await 83 | } 84 | 85 | /// Awaits a future or times out after a duration of time. 86 | pub async fn timeout(dur: Duration, f: F) -> Result 87 | where 88 | F: Future, 89 | { 90 | future::timeout(dur, f).await.map_err(|_| ()) 91 | } 92 | -------------------------------------------------------------------------------- /runtime/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Netwarps Ltd. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a 4 | // copy of this software and associated documentation files (the "Software"), 5 | // to deal in the Software without restriction, including without limitation 6 | // the rights to use, copy, modify, merge, publish, distribute, sublicense, 7 | // and/or sell copies of the Software, and to permit persons to whom the 8 | // Software is furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 14 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 19 | // DEALINGS IN THE SOFTWARE. 20 | 21 | macro_rules! cfg_async_std { 22 | ($($item:item)*) => { 23 | $( 24 | #[cfg(feature = "async-std")] 25 | $item 26 | )* 27 | } 28 | } 29 | 30 | macro_rules! cfg_tokio { 31 | ($($item:item)*) => { 32 | $( 33 | #[cfg(feature = "tokio")] 34 | $item 35 | )* 36 | } 37 | } 38 | 39 | cfg_async_std! { 40 | mod async_std; 41 | pub use self::async_std::{task, net}; 42 | } 43 | 44 | cfg_tokio! { 45 | mod tokio; 46 | pub use self::tokio::*; 47 | } 48 | 49 | pub mod limit; 50 | 51 | #[cfg(test)] 52 | mod tests { 53 | 54 | #[test] 55 | fn test_one() {} 56 | } 57 | -------------------------------------------------------------------------------- /runtime/src/tokio/mod.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Netwarps Ltd. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a 4 | // copy of this software and associated documentation files (the "Software"), 5 | // to deal in the Software without restriction, including without limitation 6 | // the rights to use, copy, modify, merge, publish, distribute, sublicense, 7 | // and/or sell copies of the Software, and to permit persons to whom the 8 | // Software is furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 14 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 19 | // DEALINGS IN THE SOFTWARE. 20 | 21 | #[allow(dead_code)] 22 | pub mod net; 23 | #[allow(dead_code)] 24 | pub mod task; 25 | -------------------------------------------------------------------------------- /rust-toolchain: -------------------------------------------------------------------------------- 1 | 1.68.2 -------------------------------------------------------------------------------- /rustfmt.toml: -------------------------------------------------------------------------------- 1 | max_width = 135 2 | tab_spaces = 4 3 | reorder_imports = true 4 | reorder_modules = true 5 | use_try_shorthand = true 6 | -------------------------------------------------------------------------------- /swarm/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "libp2prs-swarm" 3 | version = "0.4.0" 4 | license = "MIT" 5 | description = "The libp2p swarm" 6 | authors = ["Netwarps Technologies admin@paradeum.com"] 7 | repository = "https://github.com/netwarps/libp2p-rs" 8 | keywords = ["peer-to-peer", "libp2p", "networking"] 9 | categories = ["network-programming", "asynchronous"] 10 | edition = "2018" 11 | 12 | [features] 13 | async-std = ["libp2prs-runtime/async-std"] 14 | tokio = ["libp2prs-runtime/tokio"] 15 | 16 | [dependencies] 17 | async-trait = "0.1" 18 | futures = { version = "0.3", features = ["std"], default-features = false } 19 | log = "0.4" 20 | rand = "0.7" 21 | fnv = "1.0" 22 | smallvec = "1.0" 23 | prost = "0.6" 24 | void = "1" 25 | #crossbeam-epoch = "0.9" 26 | xcli = "0.5" 27 | #xcli = { git = "https://github.com/kingwel-xie/xcli-rs.git", branch = "master"} 28 | libp2prs-runtime = { path = "../runtime", version = "0.4.0" } 29 | libp2prs-core = { path = "../core", version = "0.4.0" } 30 | futures-timer = "3" 31 | 32 | [build-dependencies] 33 | prost-build = "0.6" 34 | 35 | [dev-dependencies] 36 | quickcheck = "0.9.0" 37 | rand = "0.7" 38 | env_logger = "0.8" 39 | -------------------------------------------------------------------------------- /swarm/build.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | prost_build::compile_protos(&["src/identify/structs.proto"], &["src"]).unwrap(); 3 | } 4 | -------------------------------------------------------------------------------- /swarm/src/identify/structs.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto2"; 2 | 3 | package structs; 4 | 5 | message Identify { 6 | // protocolVersion determines compatibility between peers 7 | optional string protocolVersion = 5; // e.g. ipfs/1.0.0 8 | 9 | // agentVersion is like a UserAgent string in browsers, or client version in bittorrent 10 | // includes the client name and client. 11 | optional string agentVersion = 6; // e.g. go-ipfs/0.1.0 12 | 13 | // publicKey is this node's public key (which also gives its node.ID) 14 | // - may not need to be sent, as secure channel implies it has been sent. 15 | // - then again, if we change / disable secure channel, may still want it. 16 | optional bytes publicKey = 1; 17 | 18 | // listenAddrs are the multiaddrs the sender node listens for open connections on 19 | repeated bytes listenAddrs = 2; 20 | 21 | // oservedAddr is the multiaddr of the remote endpoint that the sender node perceives 22 | // this is useful information to convey to the other side, as it helps the remote endpoint 23 | // determine whether its connection to the local peer goes through NAT. 24 | optional bytes observedAddr = 4; 25 | 26 | repeated string protocols = 3; 27 | } 28 | -------------------------------------------------------------------------------- /swarm/src/metrics/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod metric; 2 | mod snapshot; 3 | // pub mod metricmap; 4 | -------------------------------------------------------------------------------- /swarm/src/metrics/snapshot.rs: -------------------------------------------------------------------------------- 1 | // use std::sync::atomic::Ordering::SeqCst; 2 | // use std::sync::atomic::{AtomicPtr, AtomicUsize}; 3 | use std::time::SystemTime; 4 | 5 | pub struct SnapShot { 6 | total: i64, 7 | rate: f64, 8 | last_update_time: SystemTime, 9 | } 10 | 11 | impl Default for SnapShot { 12 | fn default() -> Self { 13 | SnapShot::new() 14 | } 15 | } 16 | 17 | impl SnapShot { 18 | pub fn new() -> SnapShot { 19 | SnapShot { 20 | total: 0, 21 | rate: 0.0, 22 | last_update_time: SystemTime::now(), 23 | } 24 | } 25 | 26 | pub fn set_total(&mut self, total: i64) { 27 | self.total = total; 28 | } 29 | pub fn set_rate(&mut self, rate: f64) { 30 | self.rate = rate; 31 | } 32 | pub fn set_last_update_time(&mut self, last_update_time: SystemTime) { 33 | self.last_update_time = last_update_time; 34 | } 35 | 36 | pub fn total(&self) -> i64 { 37 | self.total 38 | } 39 | pub fn rate(&self) -> f64 { 40 | self.rate 41 | } 42 | pub fn last_update_time(&self) -> SystemTime { 43 | self.last_update_time 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /swarm/src/muxer.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Netwarps Ltd. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a 4 | // copy of this software and associated documentation files (the "Software"), 5 | // to deal in the Software without restriction, including without limitation 6 | // the rights to use, copy, modify, merge, publish, distribute, sublicense, 7 | // and/or sell copies of the Software, and to permit persons to whom the 8 | // Software is furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 14 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 19 | // DEALINGS IN THE SOFTWARE. 20 | 21 | use fnv::FnvHashMap; 22 | use libp2prs_core::multistream::Negotiator; 23 | use libp2prs_core::muxing::IReadWrite; 24 | use libp2prs_core::transport::TransportError; 25 | 26 | use crate::protocol_handler::IProtocolHandler; 27 | use crate::ProtocolId; 28 | 29 | /// [`Muxer`] is used by [`Swarm`] to select and handle protocols upgrading for inbound substream. 30 | /// 31 | /// Multistream select protocol is used to proceed the protocol negotiation and selection. 32 | /// 33 | /// IProtocolHandler is the tait object of ProtocolHandler. 34 | /// 35 | pub(crate) struct Muxer { 36 | pub(crate) protocol_handlers: FnvHashMap, 37 | } 38 | 39 | impl Clone for Muxer { 40 | fn clone(&self) -> Self { 41 | Muxer { 42 | protocol_handlers: self.protocol_handlers.clone(), 43 | } 44 | } 45 | } 46 | 47 | impl Default for Muxer { 48 | fn default() -> Self { 49 | Muxer::new() 50 | } 51 | } 52 | 53 | impl Muxer { 54 | /// Add `Muxer` on top of any `ProtoclHandler`· 55 | /// 56 | /// The protocols supported by the first element have a higher priority. 57 | pub fn new() -> Self { 58 | Self { 59 | protocol_handlers: Default::default(), 60 | } 61 | } 62 | } 63 | 64 | impl Muxer { 65 | pub(crate) fn add_protocol_handler(&mut self, p: IProtocolHandler) { 66 | log::debug!("adding protocol handler: {:?}", p.protocol_info()); 67 | p.protocol_info().iter().for_each(|pid| { 68 | self.protocol_handlers.insert(pid.clone(), p.clone()); 69 | }); 70 | } 71 | 72 | pub(crate) fn supported_protocols(&self) -> impl IntoIterator + '_ { 73 | self.protocol_handlers 74 | .iter() 75 | .filter_map(|p| if p.1.client_mode() { None } else { Some(p.0.clone()) }) 76 | } 77 | 78 | pub(crate) async fn select_inbound( 79 | &mut self, 80 | socket: IReadWrite, 81 | ) -> Result<(IProtocolHandler, IReadWrite, ProtocolId), TransportError> { 82 | let protocols = self.supported_protocols(); 83 | let negotiator = Negotiator::new_with_protocols(protocols); 84 | 85 | let (proto, socket) = negotiator.negotiate(socket).await?; 86 | let handler = self.protocol_handlers.get_mut(&proto).unwrap().clone(); 87 | 88 | log::debug!("muxer select inbound {:?}", proto); 89 | 90 | Ok((handler as IProtocolHandler, socket, proto)) 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /swarm/src/network.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Parity Technologies (UK) Ltd. 2 | // Copyright 2020 Netwarps Ltd. 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a 5 | // copy of this software and associated documentation files (the "Software"), 6 | // to deal in the Software without restriction, including without limitation 7 | // the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 | // and/or sell copies of the Software, and to permit persons to whom the 9 | // Software is furnished to do so, subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 15 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 20 | // DEALINGS IN THE SOFTWARE. 21 | 22 | use libp2prs_core::PeerId; 23 | 24 | /// Information about the network obtained by [`Network::info()`]. 25 | #[derive(Debug)] 26 | pub struct NetworkInfo { 27 | /// The local Peer Id of self node. 28 | pub id: PeerId, 29 | /// The total number of connected peers. 30 | pub num_peers: usize, 31 | /// The total number of connections. 32 | pub num_connections: usize, 33 | /// The total number of pending connections, both incoming and outgoing. 34 | pub num_connections_pending: usize, 35 | /// The total number of established connections. 36 | pub num_connections_established: usize, 37 | /// The total number of active sub streams. 38 | pub num_active_streams: usize, 39 | } 40 | 41 | /// The (optional) configuration for a [`Network`]. 42 | /// 43 | /// The default configuration specifies no dedicated runtime executor, no 44 | /// connection limits, a connection event buffer size of 32, and a 45 | /// `notify_handler` buffer size of 8. 46 | #[derive(Default)] 47 | #[allow(dead_code)] 48 | pub struct NetworkConfig { 49 | /// Note that the `ManagerConfig`s runtime command buffer always provides 50 | /// one "free" slot per runtime. Thus the given total `notify_handler_buffer_size` 51 | /// exposed for configuration on the `Network` is reduced by one. 52 | //manager_config: ManagerConfig, 53 | max_outgoing: Option, 54 | max_incoming: Option, 55 | max_established_per_peer: Option, 56 | max_outgoing_per_peer: Option, 57 | } 58 | #[allow(dead_code)] 59 | impl NetworkConfig { 60 | pub fn set_incoming_limit(&mut self, n: usize) -> &mut Self { 61 | self.max_incoming = Some(n); 62 | self 63 | } 64 | 65 | pub fn set_outgoing_limit(&mut self, n: usize) -> &mut Self { 66 | self.max_outgoing = Some(n); 67 | self 68 | } 69 | 70 | pub fn set_established_per_peer_limit(&mut self, n: usize) -> &mut Self { 71 | self.max_established_per_peer = Some(n); 72 | self 73 | } 74 | 75 | pub fn set_outgoing_per_peer_limit(&mut self, n: usize) -> &mut Self { 76 | self.max_outgoing_per_peer = Some(n); 77 | self 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /transports/dns/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "libp2prs-dns" 3 | version = "0.4.0" 4 | license = "MIT" 5 | description = "DNS transport implementation for libp2p" 6 | authors = ["Netwarps Technologies admin@paradeum.com"] 7 | repository = "https://github.com/netwarps/libp2p-rs" 8 | keywords = ["peer-to-peer", "libp2p", "networking"] 9 | categories = ["network-programming", "asynchronous"] 10 | edition = "2018" 11 | 12 | [features] 13 | async-std = ["libp2prs-runtime/async-std"] 14 | tokio = ["libp2prs-runtime/tokio"] 15 | 16 | [dependencies] 17 | log = "0.4" 18 | async-trait = "0.1" 19 | libp2prs-core = { path = "../../core", version = "0.4.0" } 20 | libp2prs-runtime = { path = "../../runtime", version = "0.4.0" } 21 | 22 | [dev-dependencies] 23 | futures = { version = "0.3", features = ["std"], default-features = false } 24 | libp2prs-tcp = { path = "../tcp", version = "0.4.0", features = ["async-std"] } 25 | libp2prs-multiaddr = { path = "../../multiaddr", version = "0.4.0" } -------------------------------------------------------------------------------- /transports/tcp/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "libp2prs-tcp" 3 | version = "0.4.0" 4 | license = "MIT" 5 | description = "TCP/IP transport protocol for libp2p" 6 | authors = ["Netwarps Technologies admin@paradeum.com"] 7 | repository = "https://github.com/netwarps/libp2p-rs" 8 | keywords = ["peer-to-peer", "libp2p", "networking"] 9 | categories = ["network-programming", "asynchronous"] 10 | edition = "2018" 11 | 12 | [features] 13 | async-std = ["libp2prs-runtime/async-std"] 14 | tokio = ["libp2prs-runtime/tokio"] 15 | 16 | [dependencies] 17 | futures = { version = "0.3", features = ["std"], default-features = false } 18 | if-addrs = "0.6.4" 19 | ipnet = "2.0.0" 20 | log = "0.4" 21 | socket2 = "0.3.12" 22 | async-trait = "0.1" 23 | if-watch = "0.1.7" 24 | libp2prs-core = { path = "../../core", version = "0.4.0" } 25 | libp2prs-runtime = { path = "../../runtime", version = "0.4.0" } 26 | 27 | 28 | -------------------------------------------------------------------------------- /transports/websocket/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "libp2prs-websocket" 3 | version = "0.4.0" 4 | license = "MIT" 5 | description = "WebSocket transport for libp2p" 6 | authors = ["Netwarps Technologies admin@paradeum.com"] 7 | repository = "https://github.com/netwarps/libp2p-rs" 8 | keywords = ["peer-to-peer", "libp2p", "networking"] 9 | categories = ["network-programming", "asynchronous"] 10 | edition = "2018" 11 | 12 | [features] 13 | async-std = ["libp2prs-tcp/async-std", "libp2prs-dns/async-std"] 14 | tokio = ["libp2prs-tcp/tokio", "libp2prs-dns/tokio"] 15 | 16 | [dependencies] 17 | futures = { version = "0.3", features = ["std"], default-features = false } 18 | log = "0.4" 19 | async-tls = "0.11" 20 | rustls = "0.19" 21 | either = "1.5.3" 22 | soketto = {version = "0.4.1", features = ["deflate"] } 23 | url = "2.1" 24 | webpki = "0.21.3" 25 | webpki-roots = "0.21" 26 | async-trait = "0.1" 27 | quicksink = "0.1" 28 | pin-project = "1" 29 | libp2prs-tcp = { path = "../tcp", version = "0.4.0" } 30 | libp2prs-dns = { path = "../dns", version = "0.4.0" } 31 | libp2prs-core = { path = "../../core" , version = "0.4.0" } 32 | 33 | [dev-dependencies] 34 | env_logger = "0.8" 35 | libp2prs-runtime = { path = "../../runtime", version = "0.4.0", features = ["async-std"] } 36 | -------------------------------------------------------------------------------- /transports/websocket/src/error.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Parity Technologies (UK) Ltd. 2 | // Copyright 2020 Netwarps Ltd. 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a 5 | // copy of this software and associated documentation files (the "Software"), 6 | // to deal in the Software without restriction, including without limitation 7 | // the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 | // and/or sell copies of the Software, and to permit persons to whom the 9 | // Software is furnished to do so, subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 15 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 20 | // DEALINGS IN THE SOFTWARE. 21 | 22 | use crate::tls; 23 | use libp2prs_core::transport::TransportError; 24 | use libp2prs_core::Multiaddr; 25 | use std::{error, fmt}; 26 | 27 | /// Error in WebSockets. 28 | #[allow(dead_code)] 29 | #[derive(Debug)] 30 | pub(crate) enum WsError { 31 | /// Error in the transport layer underneath. 32 | Transport(TransportError), 33 | /// A TLS related error. 34 | Tls(tls::Error), 35 | /// Websocket handshake error. 36 | Handshake(Box), 37 | /// The configured maximum of redirects have been made. 38 | TooManyRedirects, 39 | /// A multi-address is not supported. 40 | InvalidMultiaddr(Multiaddr), 41 | /// The location header URL was invalid. 42 | InvalidRedirectLocation, 43 | /// Websocket base framing error. 44 | Base(Box), 45 | } 46 | 47 | impl fmt::Display for WsError { 48 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 49 | match self { 50 | WsError::Transport(err) => write!(f, "{}", err), 51 | WsError::Tls(err) => write!(f, "{}", err), 52 | WsError::Handshake(err) => write!(f, "{}", err), 53 | WsError::InvalidMultiaddr(ma) => write!(f, "invalid multi-address: {}", ma), 54 | WsError::TooManyRedirects => f.write_str("too many redirects"), 55 | WsError::InvalidRedirectLocation => f.write_str("invalid redirect location"), 56 | WsError::Base(err) => write!(f, "{}", err), 57 | } 58 | } 59 | } 60 | 61 | impl error::Error for WsError { 62 | fn source(&self) -> Option<&(dyn error::Error + 'static)> { 63 | match self { 64 | WsError::Transport(err) => Some(err), 65 | WsError::Tls(err) => Some(err), 66 | WsError::Handshake(err) => Some(&**err), 67 | WsError::Base(err) => Some(&**err), 68 | WsError::InvalidMultiaddr(_) | WsError::TooManyRedirects | WsError::InvalidRedirectLocation => None, 69 | } 70 | } 71 | } 72 | 73 | impl From for WsError { 74 | fn from(e: tls::Error) -> Self { 75 | WsError::Tls(e) 76 | } 77 | } 78 | --------------------------------------------------------------------------------