├── .circleci └── config.yml ├── .gitignore ├── CHANGELOG.md ├── Cargo.toml ├── LICENSE-APACHE ├── LICENSE-CC0 ├── LICENSE-MIT ├── README.md ├── src ├── bandwidth_limiter.rs ├── buffer.rs ├── compressed_bincode_channel.rs ├── event_watch.rs ├── lib.rs ├── message_channels.rs ├── packet.rs ├── packet_multiplexer.rs ├── reliable_bincode_channel.rs ├── reliable_channel.rs ├── ring_buffer.rs ├── runtime.rs ├── spsc.rs ├── unreliable_bincode_channel.rs ├── unreliable_channel.rs └── windows.rs └── tests ├── compressed_bincode_channel.rs ├── message_channels.rs ├── packet_multiplexer.rs ├── reliable_bincode_channel.rs ├── reliable_channel.rs ├── unreliable_bincode_channel.rs ├── unreliable_channel.rs └── util └── mod.rs /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | 3 | jobs: 4 | build: 5 | docker: 6 | - image: cimg/rust:1.70.0 7 | steps: 8 | - checkout 9 | - run: 10 | name: Version information 11 | command: | 12 | rustc --version 13 | cargo --version 14 | rustup --version 15 | - run: 16 | name: Calculate dependencies 17 | command: cargo generate-lockfile 18 | - restore_cache: 19 | keys: 20 | - cargo-cache-{{ arch }}-{{ checksum "Cargo.lock" }} 21 | - run: 22 | name: Check Formatting 23 | command: | 24 | rustfmt --version 25 | cargo fmt --all -- --check --color=auto 26 | - run: 27 | name: Build all targets 28 | command: cargo build --all --all-targets 29 | - run: 30 | name: Run all tests 31 | command: cargo test --all 32 | - save_cache: 33 | paths: 34 | - /usr/local/cargo/registry 35 | - target/debug/.fingerprint 36 | - target/debug/build 37 | - target/debug/deps 38 | key: cargo-cache-{{ arch }}-{{ checksum "Cargo.lock" }} 39 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | **/*.rs.bk 3 | Cargo.lock 4 | .DS_Store 5 | .#* 6 | .envrc 7 | .direnv 8 | shell.nix 9 | .dir-locals.el 10 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## [0.4] 2 | - Don't "nagle" in the reliable channel, *require* flush calls to ensure data is 3 | sent. 4 | - [API Change]: Change length limits in message channels to be uniformly `u16` 5 | and use the type system to express maximum values rather than constants. 6 | - Fix panics in reliable bincode channel with messages near upper limit due to 7 | improper buffer size. 8 | - Document that all async methods are supposed to be cancel safe. 9 | 10 | ## [0.3] 11 | - Fix the message_channels test to be less confusing, this is very important as 12 | it is currently the best (hah) example. 13 | - Make `BufferPacketPool` derive Copy if the type it wraps is Copy. 14 | - Simplify `Runtime` trait to not require an explicit `Interval`. 15 | `Runtime::Delay` wasn't even *used* prior to this, but it is the only timing 16 | requirement now and has been renamed to `Sleep` to match tokio 0.3. Neither 17 | tokio nor smol allocate as part of creating a `Sleep` / `Timer`, so having an 18 | explicit `Interval` is not really necessary to avoid e.g. allocation, and the 19 | way tokio's `Interval` works was not ideal anyway and we shouldn't rely on 20 | how it is implemented. 21 | 22 | ## [0.2] 23 | - Correctness fixes for unreliable message lengths 24 | - Performance improvements for bincode message serialization 25 | - Avoid unnecessary calls to SendExt::send 26 | - Performance improvements and fixes for internal `event_watch` events channel. 27 | - [API Change]: Update to bincode 1.3, no longer using the deprecated bincode API 28 | - [API Change]: Return `Result` in `MessageChannels` async methods on 29 | disconnection, panicking is never appropriate for a network error. Instead, 30 | the panicking version of methods in `MessageChannels` *only* panic on 31 | unregistered message types. 32 | 33 | ## [0.1.1] 34 | - Small bugifx for unreliable message channels, don't error with 35 | `SendError::TooBig` when the message will actually fit. 36 | 37 | ## [0.1.0] 38 | - Initial release 39 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "turbulence" 3 | version = "0.4.0" 4 | authors = ["kyren "] 5 | edition = "2021" 6 | description = "Tools to provide serialization, multiplexing, optional reliability, and optional compression to a game's networking." 7 | readme = "README.md" 8 | repository = "https://github.com/kyren/turbulence" 9 | documentation = "https://docs.rs/turbulence" 10 | keywords = ["gamedev", "networking"] 11 | license = "MIT OR Apache-2.0" 12 | 13 | [badges] 14 | circle-ci = { repository = "kyren/turbulence", branch = "master" } 15 | 16 | [dependencies] 17 | bincode = "1.3" 18 | byteorder = "1.3" 19 | cache-padded = "1.2" 20 | crossbeam-channel = "0.5" 21 | futures = "0.3" 22 | rustc-hash = "1.0" 23 | serde = "1.0" 24 | snap = "1.0" 25 | thiserror = "1.0" 26 | 27 | [dev-dependencies] 28 | rand = { version = "0.8", features = ["small_rng"] } 29 | serde = { version = "1.0", features = ["derive"] } 30 | -------------------------------------------------------------------------------- /LICENSE-APACHE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /LICENSE-CC0: -------------------------------------------------------------------------------- 1 | Creative Commons Legal Code 2 | 3 | CC0 1.0 Universal 4 | 5 | CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE 6 | LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN 7 | ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS 8 | INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES 9 | REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS 10 | PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM 11 | THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED 12 | HEREUNDER. 13 | 14 | Statement of Purpose 15 | 16 | The laws of most jurisdictions throughout the world automatically confer 17 | exclusive Copyright and Related Rights (defined below) upon the creator 18 | and subsequent owner(s) (each and all, an "owner") of an original work of 19 | authorship and/or a database (each, a "Work"). 20 | 21 | Certain owners wish to permanently relinquish those rights to a Work for 22 | the purpose of contributing to a commons of creative, cultural and 23 | scientific works ("Commons") that the public can reliably and without fear 24 | of later claims of infringement build upon, modify, incorporate in other 25 | works, reuse and redistribute as freely as possible in any form whatsoever 26 | and for any purposes, including without limitation commercial purposes. 27 | These owners may contribute to the Commons to promote the ideal of a free 28 | culture and the further production of creative, cultural and scientific 29 | works, or to gain reputation or greater distribution for their Work in 30 | part through the use and efforts of others. 31 | 32 | For these and/or other purposes and motivations, and without any 33 | expectation of additional consideration or compensation, the person 34 | associating CC0 with a Work (the "Affirmer"), to the extent that he or she 35 | is an owner of Copyright and Related Rights in the Work, voluntarily 36 | elects to apply CC0 to the Work and publicly distribute the Work under its 37 | terms, with knowledge of his or her Copyright and Related Rights in the 38 | Work and the meaning and intended legal effect of CC0 on those rights. 39 | 40 | 1. Copyright and Related Rights. A Work made available under CC0 may be 41 | protected by copyright and related or neighboring rights ("Copyright and 42 | Related Rights"). Copyright and Related Rights include, but are not 43 | limited to, the following: 44 | 45 | i. the right to reproduce, adapt, distribute, perform, display, 46 | communicate, and translate a Work; 47 | ii. moral rights retained by the original author(s) and/or performer(s); 48 | iii. publicity and privacy rights pertaining to a person's image or 49 | likeness depicted in a Work; 50 | iv. rights protecting against unfair competition in regards to a Work, 51 | subject to the limitations in paragraph 4(a), below; 52 | v. rights protecting the extraction, dissemination, use and reuse of data 53 | in a Work; 54 | vi. database rights (such as those arising under Directive 96/9/EC of the 55 | European Parliament and of the Council of 11 March 1996 on the legal 56 | protection of databases, and under any national implementation 57 | thereof, including any amended or successor version of such 58 | directive); and 59 | vii. other similar, equivalent or corresponding rights throughout the 60 | world based on applicable law or treaty, and any national 61 | implementations thereof. 62 | 63 | 2. Waiver. To the greatest extent permitted by, but not in contravention 64 | of, applicable law, Affirmer hereby overtly, fully, permanently, 65 | irrevocably and unconditionally waives, abandons, and surrenders all of 66 | Affirmer's Copyright and Related Rights and associated claims and causes 67 | of action, whether now known or unknown (including existing as well as 68 | future claims and causes of action), in the Work (i) in all territories 69 | worldwide, (ii) for the maximum duration provided by applicable law or 70 | treaty (including future time extensions), (iii) in any current or future 71 | medium and for any number of copies, and (iv) for any purpose whatsoever, 72 | including without limitation commercial, advertising or promotional 73 | purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each 74 | member of the public at large and to the detriment of Affirmer's heirs and 75 | successors, fully intending that such Waiver shall not be subject to 76 | revocation, rescission, cancellation, termination, or any other legal or 77 | equitable action to disrupt the quiet enjoyment of the Work by the public 78 | as contemplated by Affirmer's express Statement of Purpose. 79 | 80 | 3. Public License Fallback. Should any part of the Waiver for any reason 81 | be judged legally invalid or ineffective under applicable law, then the 82 | Waiver shall be preserved to the maximum extent permitted taking into 83 | account Affirmer's express Statement of Purpose. In addition, to the 84 | extent the Waiver is so judged Affirmer hereby grants to each affected 85 | person a royalty-free, non transferable, non sublicensable, non exclusive, 86 | irrevocable and unconditional license to exercise Affirmer's Copyright and 87 | Related Rights in the Work (i) in all territories worldwide, (ii) for the 88 | maximum duration provided by applicable law or treaty (including future 89 | time extensions), (iii) in any current or future medium and for any number 90 | of copies, and (iv) for any purpose whatsoever, including without 91 | limitation commercial, advertising or promotional purposes (the 92 | "License"). The License shall be deemed effective as of the date CC0 was 93 | applied by Affirmer to the Work. Should any part of the License for any 94 | reason be judged legally invalid or ineffective under applicable law, such 95 | partial invalidity or ineffectiveness shall not invalidate the remainder 96 | of the License, and in such case Affirmer hereby affirms that he or she 97 | will not (i) exercise any of his or her remaining Copyright and Related 98 | Rights in the Work or (ii) assert any associated claims and causes of 99 | action with respect to the Work, in either case contrary to Affirmer's 100 | express Statement of Purpose. 101 | 102 | 4. Limitations and Disclaimers. 103 | 104 | a. No trademark or patent rights held by Affirmer are waived, abandoned, 105 | surrendered, licensed or otherwise affected by this document. 106 | b. Affirmer offers the Work as-is and makes no representations or 107 | warranties of any kind concerning the Work, express, implied, 108 | statutory or otherwise, including without limitation warranties of 109 | title, merchantability, fitness for a particular purpose, non 110 | infringement, or the absence of latent or other defects, accuracy, or 111 | the present or absence of errors, whether or not discoverable, all to 112 | the greatest extent permissible under applicable law. 113 | c. Affirmer disclaims responsibility for clearing rights of other persons 114 | that may apply to the Work or any use thereof, including without 115 | limitation any person's Copyright and Related Rights in the Work. 116 | Further, Affirmer disclaims responsibility for obtaining any necessary 117 | consents, permissions or other rights required for any use of the 118 | Work. 119 | d. Affirmer understands and acknowledges that Creative Commons is not a 120 | party to this document and has no duty or obligation with respect to 121 | this CC0 or use of the Work. -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Permission is hereby granted, free of charge, to any person obtaining a copy 2 | of this software and associated documentation files (the "Software"), to deal 3 | in the Software without restriction, including without limitation the rights 4 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 5 | copies of the Software, and to permit persons to whom the Software is 6 | furnished to do so, subject to the following conditions: 7 | 8 | The above copyright notice and this permission notice shall be included in all 9 | copies or substantial portions of the Software. 10 | 11 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 12 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 13 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 14 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 15 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 16 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 17 | SOFTWARE. 18 | 19 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # turbulence 2 | 3 | *We'll get there, but it's gonna be a bumpy ride.* 4 | 5 | --- 6 | 7 | [![Build Status](https://img.shields.io/circleci/project/github/kyren/turbulence.svg)](https://circleci.com/gh/kyren/turbulence) 8 | [![Latest Version](https://img.shields.io/crates/v/turbulence.svg)](https://crates.io/crates/turbulence) 9 | [![API Documentation](https://docs.rs/turbulence/badge.svg)](https://docs.rs/turbulence) 10 | 11 | 12 | Multiplexed, optionally reliable, async, transport agnostic, reactor agnostic 13 | networking library for games. 14 | 15 | This library does not actually perform any networking itself or interact with 16 | platform networking APIs in any way, it is instead a way to take some kind of 17 | *unreliable* and *unordered* transport layer that you provide and turn it into 18 | a set of independent networking channels, each of which can optionally be made 19 | *reliable* and *ordered*. 20 | 21 | The best way right now to understand what this library is useful for probably 22 | to look at the [MessageChannels test](tests/message_channels.rs). This is the 23 | highest level, simplest API provided: it allows you to define N message types 24 | serializable with serde, define each individual channel's networking settings, 25 | and then gives you a set of handles for pushing packets into and taking packets 26 | out of this `MessageChannels` interface. The user is expected to take outgoing 27 | packets and send them out over UDP (or similar), and also read incoming packets 28 | from UDP (or similar) and pass them in. The only reliability requirement for 29 | using this is that if a packet is received from a remote, it must be intact 30 | and uncorrupted, but other than this the underlying transport does not need 31 | to provide any reliability or order guarantees. The reason that no corruption 32 | check is performed is that many transport layers already provide this for free, 33 | so it would often not be useful for `turbulence` to do that itself. Since there 34 | is no requirement for reliability, simply dropping incoming packets that do not 35 | pass a consistency check is appropriate. 36 | 37 | This library is structured in a way that provides a lot of flexibility but does 38 | not do very much to help you actually get a network connection set up between 39 | a game server and client. Setting up a UDP game server is a complex task, and 40 | this library is designed to help with one *piece* of this puzzle. 41 | 42 | --- 43 | 44 | ### What this library actually does 45 | 46 | `turbulence` currently contains two main protocols and builds some conveniences 47 | on top of them: 48 | 49 | 1) It has an unreliable, unordered messaging protocol that takes in messages 50 | that must be less than the size of a packet and coalesces them so that 51 | multiple messages are sent per packet. This is by far the simpler of the two 52 | protocols, and is appropriate for per-tick updates for things like position 53 | data, where resends of old data are not useful. 54 | 55 | 2) It has a reliable, ordered transport with flow control that is similar to 56 | TCP, but much simpler and without automatic congestion control. Instead of 57 | congestion control, the user specifies the target packet send rate as part 58 | of the protocol settings. 59 | 60 | `turbulence` then provides on top of these: 61 | 62 | 3) Reliable and unreliable channels of `bincode` serialized types. 63 | 64 | 4) A reliable channel of `bincode` serialized types that are automatically 65 | coalesced and compressed. 66 | 67 | And then finally this library also provides an API for multiplexing multiple 68 | instances of these channels across a single stream of packets and some 69 | convenient ways of constructing the channels and accessing them by message 70 | type. This is what the `MessageChannels` interface provides. 71 | 72 | ### Questions you might ask 73 | 74 | ***Why would you ever need something like this?*** 75 | 76 | You would need this library only if most or all of the following is true: 77 | 78 | 1) You have a real time, networked game where TCP or TCP-like protocols are 79 | inappropriate, and something unreliable like UDP must be used for latency 80 | reasons. 81 | 82 | 2) You have a game that needs to send both fast unreliable data like position 83 | and also stream reliable game related data such as terrain data or chat or 84 | complex entity data that is bandwidth intensive. 85 | 86 | 3) You have several independent streams of reliable data and they need to not 87 | block each other or choke off fast unreliable data. 88 | 89 | 4) It is impractical or undesirable (or impossible) to use many different OS 90 | level networking sockets, or to use existing networking libraries that hook 91 | deeply into the OS or even just assume the existence of UDP sockets. 92 | 93 | ***Why do you need this library, doesn't XYZ protocol already do this*** (Where 94 | XYZ is plain TCP, plain UDP, SCTP, QUIC, etc) 95 | 96 | In a way, this library is equivalent to having multiple UDP connections and 97 | bandwidth limited TCP connections at one time. If you can already do exactly 98 | that and that's acceptable for you, then you might consider just doing that 99 | instead of using this library! 100 | 101 | This library is also a bit similar to something like QUIC in that it gives you 102 | multiple independent channels of data which do not block each other. If QUIC 103 | eventually supports truly unrleliable, unordered messages (AFAIK currently this 104 | is only a proposed extension?), AND it has an implementation that you can use, 105 | then certainly using QUIC would be a viable option. 106 | 107 | ***So this library contains a re-implementation of something like TCP, isn't 108 | trying to implement something like that fiendishly complex and generally a bad 109 | idea?*** 110 | 111 | Probably, but since it is designed for low-ish static bandwidth limits and 112 | doesn't concern itself with congestion control, this cuts out a *lot* of the 113 | complexity. Still, this is the most complex part of this library, but it is 114 | well tested and definitely at least works *in the environments I have run 115 | so far*. It's not very complicated, it could probably be described as "the 116 | simplest TCP-like thing that you could reasonably write and use". 117 | 118 | You should not be using the reliable streams in this library in the same way 119 | that you use TCP. A good example of what *shouldn't* probably go over this 120 | library is something like streaming asset data, you should have a separate 121 | channel for data that should be streamed as fast as possible and will always be 122 | bandwidth rather than gameplay limited. 123 | 124 | The reliable streams here are for things that are normally gameplay limited but 125 | might be spikey, and where you *want* to limit the bandwidth so those spikes 126 | don't slow down more important data or slow down other players. 127 | 128 | ***Why is this library so generic? It's TOO generic, everything is based on 129 | traits like `PacketPool` and `Runtime` and it's hard to use. Why can't you just 130 | use tokio / async-std?*** 131 | 132 | The `PacketPool` trait exists not only to allow for custom packet types but 133 | also for things like the multiplexer, so it serves double duty. `Runtime` 134 | exists because I use this library in a web browser connecting to a remote 135 | server using [webrtc-unreliable](https://github.com/kyren/webrtc-unreliable), 136 | and I have to implement it manually on top of web APIs and that is 137 | currently not trivial to do. 138 | 139 | ### Current status / Future plans 140 | 141 | I've used this library in a real project over the real internet, and it 142 | definitely works. I've also tested it in-game using link conditioners to 143 | simulate various levels of packet loss and duplication and *as far as I can 144 | tell* it works as advertised. 145 | 146 | The library is usable currently, but the API should in no way be considered 147 | stable, it still may see a lot of churn. 148 | 149 | In the near future it might be useful to have other channel types that provide 150 | in-between guarantees like only reliability guarantees but not in-order 151 | guarantees or vice versa. 152 | 153 | Eventually, I'd like the reliable channels to have some sort of congestion 154 | avoidance, but this would probably need to be cooperative between reliable 155 | channels in some way. 156 | 157 | The library desperately needs better examples, especially a fully worked 158 | example using e.g. tokio and UDP, but setting up such an example is a large 159 | task by itself. 160 | 161 | ## License 162 | 163 | `turbulence` is licensed under any of: 164 | 165 | * MIT License [LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT 166 | * Apache License Version 2.0 [LICENSE-APACHE](LICENSE-APACHE) or 167 | https://opensource.org/licenses/Apache-2.0 168 | * Creative Commons CC0 1.0 Universal Public Domain Dedication 169 | [LICENSE-CC0](LICENSE-CC0) or 170 | https://creativecommons.org/publicdomain/zero/1.0/ 171 | 172 | at your option. 173 | -------------------------------------------------------------------------------- /src/bandwidth_limiter.rs: -------------------------------------------------------------------------------- 1 | use std::time::Duration; 2 | 3 | use crate::runtime::Timer; 4 | 5 | pub struct BandwidthLimiter { 6 | bandwidth: u32, 7 | burst_bandwidth: u32, 8 | bytes_available: f64, 9 | last_calculation: T::Instant, 10 | } 11 | 12 | impl BandwidthLimiter { 13 | /// The `burst_bandwidth` is the maximum amount of bandwidth credit that can accumulate. 14 | pub fn new(timer: &T, bandwidth: u32, burst_bandwidth: u32) -> Self { 15 | let last_calculation = timer.now(); 16 | BandwidthLimiter { 17 | bandwidth, 18 | burst_bandwidth, 19 | bytes_available: burst_bandwidth as f64, 20 | last_calculation, 21 | } 22 | } 23 | 24 | /// Delay until a time where there will be bandwidth available. 25 | pub fn delay_until_available(&self, timer: &T) -> Option { 26 | if self.bytes_available < 0. { 27 | Some(timer.sleep(Duration::from_secs_f64( 28 | (-self.bytes_available) / self.bandwidth as f64, 29 | ))) 30 | } else { 31 | None 32 | } 33 | } 34 | 35 | /// Actually update the amount of available bandwidth. Additional available bytes are not added 36 | /// until this method is called to add them. 37 | pub fn update_available(&mut self, timer: &T) { 38 | let now = timer.now(); 39 | self.bytes_available += timer 40 | .duration_between(self.last_calculation, now) 41 | .as_secs_f64() 42 | * self.bandwidth as f64; 43 | self.bytes_available = self.bytes_available.min(self.burst_bandwidth as f64); 44 | self.last_calculation = now; 45 | } 46 | 47 | /// The bandwidth limiter only needs to limit outgoing packets being sent at all, not their 48 | /// size, so this returns true if a non-negative amount of bytes is available. If a packet is 49 | /// sent that is larger than the available bytes, the available bytes will go negative and this 50 | /// will no longer return true. 51 | pub fn bytes_available(&self) -> bool { 52 | self.bytes_available >= 0. 53 | } 54 | 55 | /// Record that bytes were sent, possibly going into bandwidth debt. 56 | pub fn take_bytes(&mut self, bytes: u32) { 57 | self.bytes_available -= bytes as f64 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/buffer.rs: -------------------------------------------------------------------------------- 1 | use std::ops::{Deref, DerefMut}; 2 | 3 | pub use crate::packet::{Packet, PacketPool}; 4 | 5 | /// A trait for implementing `PacketPool` more easily using an allocator for statically sized 6 | /// buffers. 7 | pub trait BufferPool { 8 | type Buffer: Deref + DerefMut; 9 | 10 | fn capacity(&self) -> usize; 11 | fn acquire(&mut self) -> Self::Buffer; 12 | } 13 | 14 | /// Turns a `BufferPool` implementation into something that implements `PacketPool`. 15 | #[derive(Debug, Copy, Clone, Default)] 16 | pub struct BufferPacketPool(B); 17 | 18 | impl BufferPacketPool { 19 | pub fn new(buffer_pool: B) -> Self { 20 | BufferPacketPool(buffer_pool) 21 | } 22 | } 23 | 24 | impl PacketPool for BufferPacketPool { 25 | type Packet = BufferPacket; 26 | 27 | fn capacity(&self) -> usize { 28 | self.0.capacity() 29 | } 30 | 31 | fn acquire(&mut self) -> Self::Packet { 32 | BufferPacket { 33 | buffer: self.0.acquire(), 34 | len: 0, 35 | } 36 | } 37 | } 38 | 39 | #[derive(Debug)] 40 | pub struct BufferPacket { 41 | buffer: B, 42 | len: usize, 43 | } 44 | 45 | impl Packet for BufferPacket 46 | where 47 | B: Deref + DerefMut, 48 | { 49 | fn resize(&mut self, len: usize, val: u8) { 50 | assert!(len <= self.buffer.len()); 51 | for i in self.len..len { 52 | self.buffer[i] = val; 53 | } 54 | self.len = len; 55 | } 56 | } 57 | 58 | impl Deref for BufferPacket 59 | where 60 | B: Deref, 61 | { 62 | type Target = [u8]; 63 | 64 | fn deref(&self) -> &[u8] { 65 | &self.buffer[0..self.len] 66 | } 67 | } 68 | 69 | impl DerefMut for BufferPacket 70 | where 71 | B: Deref + DerefMut, 72 | { 73 | fn deref_mut(&mut self) -> &mut [u8] { 74 | &mut self.buffer[0..self.len] 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/compressed_bincode_channel.rs: -------------------------------------------------------------------------------- 1 | use std::{ 2 | convert::TryInto, 3 | marker::PhantomData, 4 | task::{Context, Poll}, 5 | u16, 6 | }; 7 | 8 | use bincode::Options as _; 9 | use byteorder::{ByteOrder, LittleEndian}; 10 | use futures::{future, ready, task}; 11 | use serde::{de::DeserializeOwned, Serialize}; 12 | use snap::raw::{decompress_len, max_compress_len, Decoder as SnapDecoder, Encoder as SnapEncoder}; 13 | use thiserror::Error; 14 | 15 | use crate::reliable_channel::{self, ReliableChannel}; 16 | 17 | /// The maximum serialized length of a `CompressedBincodeChannel` message. This also serves as 18 | /// the maximum size of a compressed chunk of messages, but it is guaranteed that any message <= 19 | /// `MAX_MESSAGE_LEN` can be sent, even if it cannot be compressed. 20 | pub const MAX_MESSAGE_LEN: u16 = u16::MAX; 21 | 22 | #[derive(Debug, Error)] 23 | pub enum SendError { 24 | /// Fatal internal channel error. 25 | #[error("reliable channel error error: {0}")] 26 | ReliableChannelError(#[from] reliable_channel::Error), 27 | /// Non-fatal error, no message is sent. 28 | #[error("bincode serialization error: {0}")] 29 | BincodeError(#[from] bincode::Error), 30 | } 31 | 32 | #[derive(Debug, Error)] 33 | pub enum RecvError { 34 | /// Fatal internal channel error. 35 | #[error("reliable channel error error: {0}")] 36 | ReliableChannelError(#[from] reliable_channel::Error), 37 | /// Fatal error, indicates corruption or protocol mismatch. 38 | #[error("Snappy serialization error: {0}")] 39 | SnapError(#[from] snap::Error), 40 | /// Fatal error, stream becomes desynchronized, individual serialized types are not length 41 | /// prefixed. 42 | #[error("bincode serialization error: {0}")] 43 | BincodeError(#[from] bincode::Error), 44 | } 45 | 46 | /// Wraps a `ReliableMessageChannel` and reliably sends a single message type serialized with 47 | /// `bincode` and compressed with `snap`. 48 | /// 49 | /// Messages are written in large blocks to aid compression. Messages are serialized end to end, and 50 | /// when a block reaches the maximum configured size (or `flush` is called), the block is compressed 51 | /// and sent as a single message. 52 | /// 53 | /// This saves space from the compression and also from the reduced message header overhead per 54 | /// individual message. 55 | pub struct CompressedBincodeChannel { 56 | channel: ReliableChannel, 57 | 58 | send_chunk: Vec, 59 | 60 | write_buffer: Vec, 61 | write_pos: usize, 62 | 63 | read_buffer: Vec, 64 | read_pos: usize, 65 | 66 | recv_chunk: Vec, 67 | recv_pos: usize, 68 | 69 | encoder: SnapEncoder, 70 | decoder: SnapDecoder, 71 | } 72 | 73 | impl From for CompressedBincodeChannel { 74 | fn from(channel: ReliableChannel) -> Self { 75 | Self::new(channel) 76 | } 77 | } 78 | 79 | impl CompressedBincodeChannel { 80 | pub fn new(channel: ReliableChannel) -> Self { 81 | CompressedBincodeChannel { 82 | channel, 83 | send_chunk: Vec::new(), 84 | write_buffer: Vec::new(), 85 | write_pos: 0, 86 | read_buffer: Vec::new(), 87 | read_pos: 0, 88 | recv_chunk: Vec::new(), 89 | recv_pos: 0, 90 | encoder: SnapEncoder::new(), 91 | decoder: SnapDecoder::new(), 92 | } 93 | } 94 | 95 | pub fn into_inner(self) -> ReliableChannel { 96 | self.channel 97 | } 98 | 99 | /// Send the given message. 100 | /// 101 | /// This method is cancel safe, it will never partially send a message, and completes 102 | /// immediately upon successfully queuing a message to send. 103 | pub async fn send(&mut self, msg: &M) -> Result<(), SendError> { 104 | future::poll_fn(|cx| self.poll_send(cx, msg)).await 105 | } 106 | 107 | pub fn try_send(&mut self, msg: &M) -> Result { 108 | match self.poll_send(&mut Context::from_waker(task::noop_waker_ref()), msg) { 109 | Poll::Pending => Ok(false), 110 | Poll::Ready(Ok(())) => Ok(true), 111 | Poll::Ready(Err(err)) => Err(err), 112 | } 113 | } 114 | 115 | /// Finish sending the current block of messages, compressing them and sending them over the 116 | /// reliable channel. 117 | /// 118 | /// This method is cancel safe. 119 | pub async fn flush(&mut self) -> Result<(), reliable_channel::Error> { 120 | future::poll_fn(|cx| self.poll_flush(cx)).await 121 | } 122 | 123 | pub fn try_flush(&mut self) -> Result { 124 | match self.poll_flush(&mut Context::from_waker(task::noop_waker_ref())) { 125 | Poll::Pending => Ok(false), 126 | Poll::Ready(Ok(())) => Ok(true), 127 | Poll::Ready(Err(err)) => Err(err), 128 | } 129 | } 130 | 131 | /// Receive a message. 132 | /// 133 | /// This method is cancel safe, it will never partially receive a message and will never drop a 134 | /// received message. 135 | pub async fn recv(&mut self) -> Result { 136 | future::poll_fn(|cx| self.poll_recv_ready(cx)).await?; 137 | Ok(self.recv_next()?) 138 | } 139 | 140 | pub fn try_recv(&mut self) -> Result, RecvError> { 141 | match self.poll_recv::(&mut Context::from_waker(task::noop_waker_ref())) { 142 | Poll::Pending => Ok(None), 143 | Poll::Ready(Ok(val)) => Ok(Some(val)), 144 | Poll::Ready(Err(err)) => Err(err), 145 | } 146 | } 147 | 148 | pub fn poll_send( 149 | &mut self, 150 | cx: &mut Context, 151 | msg: &M, 152 | ) -> Poll> { 153 | let bincode_config = self.bincode_config(); 154 | 155 | let serialized_len = bincode_config.serialized_size(msg)?; 156 | if self.send_chunk.len() as u64 + serialized_len > MAX_MESSAGE_LEN as u64 { 157 | ready!(self.poll_write_send_chunk(cx))?; 158 | } 159 | 160 | bincode_config.serialize_into(&mut self.send_chunk, msg)?; 161 | 162 | Poll::Ready(Ok(())) 163 | } 164 | 165 | pub fn poll_flush(&mut self, cx: &mut Context) -> Poll> { 166 | ready!(self.poll_write_send_chunk(cx))?; 167 | ready!(self.poll_finish_write(cx))?; 168 | self.channel.flush()?; 169 | Poll::Ready(Ok(())) 170 | } 171 | 172 | pub fn poll_recv( 173 | &mut self, 174 | cx: &mut Context, 175 | ) -> Poll> { 176 | ready!(self.poll_recv_ready(cx))?; 177 | Poll::Ready(Ok(self.recv_next::()?)) 178 | } 179 | 180 | fn poll_recv_ready(&mut self, cx: &mut Context) -> Poll> { 181 | loop { 182 | if self.recv_pos < self.recv_chunk.len() { 183 | return Poll::Ready(Ok(())); 184 | } 185 | 186 | if self.read_pos < 3 { 187 | self.read_buffer.resize(3, 0); 188 | ready!(self.poll_finish_read(cx))?; 189 | } 190 | 191 | let compressed = self.read_buffer[0] != 0; 192 | let chunk_len = LittleEndian::read_u16(&self.read_buffer[1..3]); 193 | self.read_buffer.resize(chunk_len as usize + 3, 0); 194 | ready!(self.poll_finish_read(cx))?; 195 | 196 | if compressed { 197 | let decompressed_len = decompress_len(&self.read_buffer[3..])?; 198 | self.recv_chunk 199 | .resize(decompressed_len.min(MAX_MESSAGE_LEN as usize), 0); 200 | self.decoder 201 | .decompress(&self.read_buffer[3..], &mut self.recv_chunk)?; 202 | } else { 203 | self.recv_chunk.resize(chunk_len as usize, 0); 204 | self.recv_chunk.copy_from_slice(&self.read_buffer[3..]); 205 | } 206 | 207 | self.recv_pos = 0; 208 | self.read_pos = 0; 209 | } 210 | } 211 | 212 | fn recv_next(&mut self) -> Result { 213 | let bincode_config = self.bincode_config(); 214 | let mut reader = &self.recv_chunk[self.recv_pos..]; 215 | let msg = bincode_config.deserialize_from(&mut reader)?; 216 | self.recv_pos = self.recv_chunk.len() - reader.len(); 217 | Ok(msg) 218 | } 219 | 220 | fn poll_write_send_chunk( 221 | &mut self, 222 | cx: &mut Context, 223 | ) -> Poll> { 224 | if !self.send_chunk.is_empty() { 225 | ready!(self.poll_finish_write(cx))?; 226 | 227 | self.write_pos = 0; 228 | self.write_buffer 229 | .resize(max_compress_len(self.send_chunk.len()) + 3, 0); 230 | // Should not error, `write_buffer` is correctly sized and is less than `2^32 - 1` 231 | let compressed_len = self 232 | .encoder 233 | .compress(&self.send_chunk, &mut self.write_buffer[3..]) 234 | .expect("unexpected snap encoder error"); 235 | self.write_buffer.truncate(compressed_len + 3); 236 | if compressed_len >= self.send_chunk.len() { 237 | // If our compressed size is worse than our uncompressed size, write the original 238 | // chunk. 239 | self.write_buffer.truncate(self.send_chunk.len() + 3); 240 | self.write_buffer[3..].copy_from_slice(&self.send_chunk); 241 | // An initial 0 means uncompressed 242 | self.write_buffer[0] = 0; 243 | LittleEndian::write_u16( 244 | &mut self.write_buffer[1..3], 245 | (self.send_chunk.len()).try_into().unwrap(), 246 | ); 247 | } else { 248 | // An initial 1 means compressed 249 | self.write_buffer[0] = 1; 250 | LittleEndian::write_u16( 251 | &mut self.write_buffer[1..3], 252 | (compressed_len).try_into().unwrap(), 253 | ); 254 | } 255 | 256 | self.send_chunk.clear(); 257 | } 258 | 259 | Poll::Ready(Ok(())) 260 | } 261 | 262 | fn poll_finish_write(&mut self, cx: &mut Context) -> Poll> { 263 | while self.write_pos < self.write_buffer.len() { 264 | let len = ready!(self 265 | .channel 266 | .poll_write(cx, &self.write_buffer[self.write_pos..]))?; 267 | self.write_pos += len; 268 | } 269 | Poll::Ready(Ok(())) 270 | } 271 | 272 | fn poll_finish_read(&mut self, cx: &mut Context) -> Poll> { 273 | while self.read_pos < self.read_buffer.len() { 274 | let len = ready!(self 275 | .channel 276 | .poll_read(cx, &mut self.read_buffer[self.read_pos..]))?; 277 | self.read_pos += len; 278 | } 279 | Poll::Ready(Ok(())) 280 | } 281 | 282 | fn bincode_config(&self) -> impl bincode::Options + Copy { 283 | bincode::options().with_limit(MAX_MESSAGE_LEN as u64) 284 | } 285 | } 286 | 287 | /// Wrapper over an `CompressedBincodeChannel` that only allows a single message type. 288 | pub struct CompressedTypedChannel { 289 | channel: CompressedBincodeChannel, 290 | _phantom: PhantomData, 291 | } 292 | 293 | impl From for CompressedTypedChannel { 294 | fn from(channel: ReliableChannel) -> Self { 295 | Self::new(channel) 296 | } 297 | } 298 | 299 | impl CompressedTypedChannel { 300 | pub fn new(channel: ReliableChannel) -> Self { 301 | CompressedTypedChannel { 302 | channel: CompressedBincodeChannel::new(channel), 303 | _phantom: PhantomData, 304 | } 305 | } 306 | 307 | pub fn into_inner(self) -> ReliableChannel { 308 | self.channel.into_inner() 309 | } 310 | 311 | pub async fn flush(&mut self) -> Result<(), reliable_channel::Error> { 312 | self.channel.flush().await 313 | } 314 | 315 | pub fn try_flush(&mut self) -> Result { 316 | self.channel.try_flush() 317 | } 318 | 319 | pub fn poll_flush(&mut self, cx: &mut Context) -> Poll> { 320 | self.channel.poll_flush(cx) 321 | } 322 | } 323 | 324 | impl CompressedTypedChannel { 325 | pub async fn send(&mut self, msg: &M) -> Result<(), SendError> { 326 | self.channel.send(msg).await 327 | } 328 | 329 | pub fn try_send(&mut self, msg: &M) -> Result { 330 | self.channel.try_send(msg) 331 | } 332 | 333 | pub fn poll_send(&mut self, cx: &mut Context, msg: &M) -> Poll> { 334 | self.channel.poll_send(cx, msg) 335 | } 336 | } 337 | 338 | impl CompressedTypedChannel { 339 | pub async fn recv(&mut self) -> Result { 340 | self.channel.recv::().await 341 | } 342 | 343 | pub fn try_recv(&mut self) -> Result, RecvError> { 344 | self.channel.try_recv::() 345 | } 346 | 347 | pub fn poll_recv(&mut self, cx: &mut Context) -> Poll> { 348 | self.channel.poll_recv::(cx) 349 | } 350 | } 351 | -------------------------------------------------------------------------------- /src/event_watch.rs: -------------------------------------------------------------------------------- 1 | use std::{ 2 | sync::{ 3 | atomic::{self, AtomicBool}, 4 | Arc, 5 | }, 6 | task::Poll, 7 | }; 8 | 9 | use futures::{future, task::AtomicWaker}; 10 | 11 | /// Creates a multi-producer single-consumer stream of events with certain beneficial properties. 12 | /// 13 | /// If a receiver is waiting on a signaled event, calling `Sender::signal` will wakeup the receiver 14 | /// as normal. However, if the receiver is *not* waiting on a signaled event and `Sender::signal` 15 | /// has been called since the last time the `Receiver::wait` was called, then calling 16 | /// `Receiver::wait` again will immediately resolve. In this way, the receiver is prevented from 17 | /// possibly missing events. 18 | /// 19 | /// In other words, calling `Sender::signal` will always do one of two things: 20 | /// 1) Wake up a currently waiting receiver 21 | /// 2) Make the next call to `Receiver::wait` resolve immediately 22 | /// 23 | /// Multiple calls to `Sender::signal` events will however *not* cause *multiple* calls to 24 | /// `Receiver::wait` to resolve immediately, only the very next call to `Receiver::wait`. 25 | /// 26 | /// You can look at this as a specialized version a bounded channel of `()` with capacity 1. 27 | pub fn channel() -> (Sender, Receiver) { 28 | let state = Arc::new(State { 29 | waker: AtomicWaker::new(), 30 | signaled: AtomicBool::new(false), 31 | }); 32 | 33 | let sender_state = Arc::clone(&state); 34 | 35 | (Sender(sender_state), Receiver(state)) 36 | } 37 | 38 | #[derive(Debug, Clone)] 39 | pub struct Sender(Arc); 40 | 41 | impl Sender { 42 | pub fn signal(&self) { 43 | self.0.signaled.store(true, atomic::Ordering::SeqCst); 44 | self.0.waker.wake() 45 | } 46 | } 47 | 48 | #[derive(Debug)] 49 | pub struct Receiver(Arc); 50 | 51 | impl Receiver { 52 | pub async fn wait(&mut self) { 53 | future::poll_fn(|cx| { 54 | if self.0.signaled.swap(false, atomic::Ordering::SeqCst) { 55 | Poll::Ready(()) 56 | } else { 57 | self.0.waker.register(cx.waker()); 58 | if self.0.signaled.swap(false, atomic::Ordering::SeqCst) { 59 | Poll::Ready(()) 60 | } else { 61 | Poll::Pending 62 | } 63 | } 64 | }) 65 | .await 66 | } 67 | } 68 | 69 | #[derive(Debug)] 70 | struct State { 71 | waker: AtomicWaker, 72 | signaled: AtomicBool, 73 | } 74 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | mod bandwidth_limiter; 2 | pub mod buffer; 3 | pub mod compressed_bincode_channel; 4 | mod event_watch; 5 | pub mod message_channels; 6 | pub mod packet; 7 | pub mod packet_multiplexer; 8 | pub mod reliable_bincode_channel; 9 | pub mod reliable_channel; 10 | mod ring_buffer; 11 | pub mod runtime; 12 | pub mod spsc; 13 | pub mod unreliable_bincode_channel; 14 | pub mod unreliable_channel; 15 | mod windows; 16 | 17 | pub use self::{ 18 | buffer::{BufferPacket, BufferPacketPool, BufferPool}, 19 | compressed_bincode_channel::{CompressedBincodeChannel, CompressedTypedChannel}, 20 | message_channels::{ 21 | MessageChannelMode, MessageChannelSettings, MessageChannels, MessageChannelsBuilder, 22 | }, 23 | packet::{Packet, PacketPool, MAX_PACKET_LEN}, 24 | packet_multiplexer::{ 25 | ChannelStatistics, ChannelTotals, IncomingMultiplexedPackets, MuxPacket, MuxPacketPool, 26 | OutgoingMultiplexedPackets, PacketChannel, PacketMultiplexer, 27 | }, 28 | reliable_bincode_channel::{ReliableBincodeChannel, ReliableTypedChannel}, 29 | reliable_channel::ReliableChannel, 30 | runtime::{Spawn, Timer}, 31 | unreliable_bincode_channel::{UnreliableBincodeChannel, UnreliableTypedChannel}, 32 | unreliable_channel::UnreliableChannel, 33 | }; 34 | -------------------------------------------------------------------------------- /src/message_channels.rs: -------------------------------------------------------------------------------- 1 | use std::{ 2 | any::{type_name, Any, TypeId}, 3 | collections::{hash_map, HashMap, HashSet}, 4 | error::Error, 5 | task::{Context, Poll}, 6 | }; 7 | 8 | use futures::{ 9 | future::{self, BoxFuture, RemoteHandle}, 10 | ready, select, 11 | stream::FuturesUnordered, 12 | FutureExt, SinkExt, StreamExt, TryFutureExt, 13 | }; 14 | use rustc_hash::FxHashMap; 15 | use serde::{de::DeserializeOwned, Serialize}; 16 | use thiserror::Error; 17 | 18 | use crate::{ 19 | event_watch, 20 | packet::PacketPool, 21 | packet_multiplexer::{ChannelStatistics, PacketChannel, PacketMultiplexer}, 22 | reliable_channel, 23 | runtime::{Spawn, Timer}, 24 | spsc::{self, TryRecvError}, 25 | unreliable_channel, CompressedTypedChannel, MuxPacketPool, ReliableChannel, 26 | ReliableTypedChannel, UnreliableChannel, UnreliableTypedChannel, 27 | }; 28 | 29 | // TODO: Message channels are currently always full-duplex, because the unreliable / reliable 30 | // channels backing them are always full-duplex. We could add configuration to limit a channel to 31 | // send or receive only, and to error if the remote sends to a send-only channel. 32 | #[derive(Debug, Clone, PartialEq)] 33 | pub struct MessageChannelSettings { 34 | pub channel: PacketChannel, 35 | pub channel_mode: MessageChannelMode, 36 | /// The buffer size for the spsc channel of messages that transports messages of this type to / 37 | /// from the network task. 38 | pub message_buffer_size: usize, 39 | /// The buffer size for the spsc channel of packets for this message type that transports 40 | /// packets to / from the packet multiplexer. 41 | pub packet_buffer_size: usize, 42 | } 43 | 44 | #[derive(Debug, Clone, PartialEq)] 45 | pub enum MessageChannelMode { 46 | Unreliable(unreliable_channel::Settings), 47 | Reliable(reliable_channel::Settings), 48 | Compressed(reliable_channel::Settings), 49 | } 50 | 51 | pub trait ChannelMessage: Serialize + DeserializeOwned + Send + Sync + 'static {} 52 | 53 | impl ChannelMessage for T {} 54 | 55 | #[derive(Debug, Error)] 56 | pub enum ChannelAlreadyRegistered { 57 | #[error("message type already registered")] 58 | MessageType, 59 | #[error("channel already registered")] 60 | Channel, 61 | } 62 | 63 | pub type TaskError = Box; 64 | 65 | #[derive(Debug, Error)] 66 | #[error("network task for message type {type_name:?} has errored: {error}")] 67 | pub struct ChannelTaskError { 68 | pub type_name: &'static str, 69 | pub error: TaskError, 70 | } 71 | 72 | pub struct MessageChannelsBuilder 73 | where 74 | S: Spawn, 75 | T: Timer, 76 | P: PacketPool, 77 | { 78 | spawn: S, 79 | timer: T, 80 | pool: P, 81 | channels: HashSet, 82 | register_fns: HashMap)>, 83 | } 84 | 85 | impl MessageChannelsBuilder 86 | where 87 | S: Spawn, 88 | T: Timer, 89 | P: PacketPool, 90 | { 91 | pub fn new(spawn: S, timer: T, pool: P) -> Self { 92 | MessageChannelsBuilder { 93 | spawn, 94 | timer, 95 | pool, 96 | channels: HashSet::new(), 97 | register_fns: HashMap::new(), 98 | } 99 | } 100 | } 101 | 102 | impl MessageChannelsBuilder 103 | where 104 | S: Spawn + Clone + 'static, 105 | T: Timer + Clone + 'static, 106 | P: PacketPool + Clone + Send + 'static, 107 | P::Packet: Send, 108 | { 109 | /// Register this message type on the constructed `MessageChannels`, using the given channel 110 | /// settings. 111 | /// 112 | /// Can only be called once per message type, will error if it is called with the same message 113 | /// type or channel number more than once. 114 | pub fn register( 115 | &mut self, 116 | settings: MessageChannelSettings, 117 | ) -> Result<(), ChannelAlreadyRegistered> { 118 | if !self.channels.insert(settings.channel) { 119 | return Err(ChannelAlreadyRegistered::Channel); 120 | } 121 | 122 | match self.register_fns.entry(TypeId::of::()) { 123 | hash_map::Entry::Occupied(_) => Err(ChannelAlreadyRegistered::MessageType), 124 | hash_map::Entry::Vacant(vacant) => { 125 | vacant.insert(( 126 | type_name::(), 127 | settings, 128 | register_message_type::, 129 | )); 130 | Ok(()) 131 | } 132 | } 133 | } 134 | 135 | /// Build a `MessageChannels` instance that can send and receive all of the registered message 136 | /// types via channels on the given packet multiplexer. 137 | pub fn build(self, multiplexer: &mut PacketMultiplexer) -> MessageChannels { 138 | let Self { 139 | spawn, 140 | timer, 141 | pool, 142 | register_fns, 143 | .. 144 | } = self; 145 | let mut channels_map = ChannelsMap::default(); 146 | let mut tasks: FuturesUnordered<_> = register_fns 147 | .into_iter() 148 | .map(|(_, (type_name, settings, register_fn))| { 149 | register_fn( 150 | settings, 151 | spawn.clone(), 152 | timer.clone(), 153 | pool.clone(), 154 | multiplexer, 155 | &mut channels_map, 156 | ) 157 | .map_err(move |error| ChannelTaskError { type_name, error }) 158 | }) 159 | .collect(); 160 | 161 | let (remote, remote_handle) = async move { 162 | match tasks.next().await { 163 | None => ChannelTaskError { 164 | type_name: "none", 165 | error: "no channel tasks to run".to_owned().into(), 166 | }, 167 | Some(Ok(())) => panic!("channel tasks only return errors"), 168 | Some(Err(err)) => err, 169 | } 170 | } 171 | .remote_handle(); 172 | spawn.spawn(remote); 173 | 174 | MessageChannels { 175 | disconnected: false, 176 | task: remote_handle, 177 | channels: channels_map, 178 | } 179 | } 180 | } 181 | 182 | #[derive(Debug, Error)] 183 | #[error("no such message type `{0}` registered")] 184 | pub struct MessageTypeUnregistered(&'static str); 185 | 186 | #[derive(Debug, Error)] 187 | #[error("`MessageChannels` instance has become disconnected")] 188 | pub struct MessageChannelsDisconnected; 189 | 190 | #[derive(Debug, Error)] 191 | pub enum TryAsyncMessageError { 192 | #[error(transparent)] 193 | Unregistered(#[from] MessageTypeUnregistered), 194 | #[error(transparent)] 195 | Disconnected(#[from] MessageChannelsDisconnected), 196 | } 197 | 198 | /// Manages a set of channels through a packet multiplexer, where each channel is associated with 199 | /// exactly one message type. 200 | /// 201 | /// Acts as a bridge between the sync and async worlds. Provides sync methods to send and receive 202 | /// messages that do not block or error. Has simplified error handling, is if any of the backing 203 | /// tasks end in an error or if the backing packet channels are dropped, the `MessageChannels` will 204 | /// permanently go into a "disconnected" state. 205 | /// 206 | /// Additionally still provides async versions of methods to send and receive messages that share 207 | /// the same simplified error handling, which may be useful during startup or shutdown. 208 | #[derive(Debug)] 209 | pub struct MessageChannels { 210 | disconnected: bool, 211 | task: RemoteHandle, 212 | channels: ChannelsMap, 213 | } 214 | 215 | impl MessageChannels { 216 | /// Returns whether this `MessageChannels` has become disconnected because the backing network 217 | /// task has errored. 218 | /// 219 | /// Once it has become disconnected, a `MessageChannels` is permanently in this errored state. 220 | /// You can receive the error from the task by calling `MessageChannels::recv_err`. 221 | pub fn is_connected(&self) -> bool { 222 | !self.disconnected 223 | } 224 | 225 | /// Consume this `MessageChannels` and receive the networking task shutdown error. 226 | /// 227 | /// If this `MessageChannels` is disconnected, returns the error that caused it to become 228 | /// disconnected. If it is not disconnected, it will become disconnected by calling this and 229 | /// return that error. 230 | pub async fn recv_err(self) -> ChannelTaskError { 231 | drop(self.channels); 232 | self.task.await 233 | } 234 | 235 | /// Send the given message on the channel associated with its message type. 236 | /// 237 | /// In order to ensure delivery, `flush` should be called for the same message type to 238 | /// immediately send any buffered messages. 239 | /// 240 | /// If the spsc channel for this message type is full, will return the message that was sent 241 | /// back to the caller. If the message was successfully put onto the outgoing spsc channel, will 242 | /// return None. 243 | /// 244 | /// # Panics 245 | /// Panics if this message type was not registered with the `MessageChannelsBuilder` used to 246 | /// build this `MessageChannels` instance. 247 | pub fn send(&mut self, message: M) -> Option { 248 | self.try_send(message).unwrap() 249 | } 250 | 251 | /// Like `MessageChannels::send` but errors instead of panicking when the message type is 252 | /// unregistered. 253 | pub fn try_send( 254 | &mut self, 255 | message: M, 256 | ) -> Result, MessageTypeUnregistered> { 257 | let channels = self.channels.get_mut::()?; 258 | 259 | Ok(if self.disconnected { 260 | Some(message) 261 | } else if let Err(err) = channels.outgoing_sender.try_send(message) { 262 | if err.is_disconnected() { 263 | self.disconnected = true; 264 | } 265 | Some(err.into_inner()) 266 | } else { 267 | None 268 | }) 269 | } 270 | 271 | /// Any async version of `MessageChannels::send`, sends the given message on the 272 | /// channel associated with its message type but waits if the channel is full. Like 273 | /// `MessageChannels::send`, `MessageChannels::flush` must still be called afterwards in order 274 | /// to ensure delivery. 275 | /// 276 | /// This method is cancel safe, it will never partially send a message, though canceling it may 277 | /// or may not buffer a message to be sent. 278 | /// 279 | /// # Panics 280 | /// Panics if this message type is not registered. 281 | pub async fn async_send( 282 | &mut self, 283 | message: M, 284 | ) -> Result<(), MessageChannelsDisconnected> { 285 | self.try_async_send(message).await.map_err(|e| match e { 286 | TryAsyncMessageError::Unregistered(e) => panic!("{}", e), 287 | TryAsyncMessageError::Disconnected(e) => e, 288 | }) 289 | } 290 | 291 | /// Like `MessageChannels::async_send` but errors instead of panicking when the message type is 292 | /// unregistered. 293 | pub async fn try_async_send( 294 | &mut self, 295 | message: M, 296 | ) -> Result<(), TryAsyncMessageError> { 297 | let channels = self.channels.get_mut::()?; 298 | 299 | if self.disconnected { 300 | Err(MessageChannelsDisconnected.into()) 301 | } else { 302 | let res = channels.outgoing_sender.send(message).await; 303 | 304 | if res.is_err() { 305 | self.disconnected = true; 306 | Err(MessageChannelsDisconnected.into()) 307 | } else { 308 | Ok(()) 309 | } 310 | } 311 | } 312 | 313 | /// Immediately send any buffered messages for this message type. Messages may not be delivered 314 | /// unless `flush` is called after any `send` calls. 315 | /// 316 | /// # Panics 317 | /// Panics if this message type was not registered with the `MessageChannelsBuilder` used to 318 | /// build this `MessageChannels` instance. 319 | pub fn flush(&mut self) { 320 | self.try_flush::().unwrap(); 321 | } 322 | 323 | /// Like `MessageChannels::flush` but errors instead of panicking when the message type is 324 | /// unregistered. 325 | pub fn try_flush(&mut self) -> Result<(), MessageTypeUnregistered> { 326 | self.channels.get_mut::()?.flush_sender.signal(); 327 | Ok(()) 328 | } 329 | 330 | /// Receive an incoming message on the channel associated with this mesage type, if one is 331 | /// available. 332 | /// 333 | /// # Panics 334 | /// Panics if this message type was not registered with the `MessageChannelsBuilder` used to 335 | /// build this `MessageChannels` instance. 336 | pub fn recv(&mut self) -> Option { 337 | self.try_recv().unwrap() 338 | } 339 | 340 | /// Like `MessageChannels::recv` but errors instead of panicking when the message type is 341 | /// unregistered. 342 | pub fn try_recv(&mut self) -> Result, MessageTypeUnregistered> { 343 | let channels = self.channels.get_mut::()?; 344 | 345 | Ok(if self.disconnected { 346 | None 347 | } else { 348 | match channels.incoming_receiver.try_recv() { 349 | Ok(msg) => Some(msg), 350 | Err(err) => { 351 | if err.is_disconnected() { 352 | self.disconnected = true; 353 | } 354 | None 355 | } 356 | } 357 | }) 358 | } 359 | 360 | /// Any async version of `MessageChannels::receive`, receives an incoming message on the channel 361 | /// associated with its message type but waits if there is no message available. 362 | /// 363 | /// This method is cancel safe, it will never partially read a message or drop received 364 | /// messages. 365 | /// 366 | /// # Panics 367 | /// Panics if this message type is not registered. 368 | pub async fn async_recv( 369 | &mut self, 370 | ) -> Result { 371 | self.try_async_recv().await.map_err(|e| match e { 372 | TryAsyncMessageError::Unregistered(e) => panic!("{}", e), 373 | TryAsyncMessageError::Disconnected(e) => e, 374 | }) 375 | } 376 | 377 | /// Like `MessageChannels::async_recv` but errors instead of panicking when the message type is 378 | /// unregistered. 379 | pub async fn try_async_recv(&mut self) -> Result { 380 | let channels = self.channels.get_mut::()?; 381 | 382 | if self.disconnected { 383 | Err(MessageChannelsDisconnected.into()) 384 | } else if let Some(message) = channels.incoming_receiver.next().await { 385 | Ok(message) 386 | } else { 387 | self.disconnected = true; 388 | Err(MessageChannelsDisconnected.into()) 389 | } 390 | } 391 | 392 | pub fn statistics(&self) -> &ChannelStatistics { 393 | self.try_statistics::().unwrap() 394 | } 395 | 396 | pub fn try_statistics( 397 | &self, 398 | ) -> Result<&ChannelStatistics, MessageTypeUnregistered> { 399 | Ok(&self.channels.get::()?.statistics) 400 | } 401 | } 402 | 403 | type ChannelTask = BoxFuture<'static, Result<(), TaskError>>; 404 | type RegisterFn = fn( 405 | MessageChannelSettings, 406 | S, 407 | T, 408 | P, 409 | &mut PacketMultiplexer<

::Packet>, 410 | &mut ChannelsMap, 411 | ) -> ChannelTask; 412 | 413 | #[derive(Debug, Error)] 414 | #[error("channel has been disconnected")] 415 | struct ChannelDisconnected; 416 | 417 | struct ChannelSet { 418 | outgoing_sender: spsc::Sender, 419 | incoming_receiver: spsc::Receiver, 420 | flush_sender: event_watch::Sender, 421 | statistics: ChannelStatistics, 422 | } 423 | 424 | #[derive(Debug, Default)] 425 | struct ChannelsMap(FxHashMap>); 426 | 427 | impl ChannelsMap { 428 | fn insert(&mut self, channel_set: ChannelSet) -> bool { 429 | self.0 430 | .insert(TypeId::of::(), Box::new(channel_set)) 431 | .is_none() 432 | } 433 | 434 | fn get(&self) -> Result<&ChannelSet, MessageTypeUnregistered> { 435 | Ok(self 436 | .0 437 | .get(&TypeId::of::()) 438 | .ok_or_else(|| MessageTypeUnregistered(type_name::()))? 439 | .downcast_ref() 440 | .unwrap()) 441 | } 442 | 443 | fn get_mut( 444 | &mut self, 445 | ) -> Result<&mut ChannelSet, MessageTypeUnregistered> { 446 | Ok(self 447 | .0 448 | .get_mut(&TypeId::of::()) 449 | .ok_or_else(|| MessageTypeUnregistered(type_name::()))? 450 | .downcast_mut() 451 | .unwrap()) 452 | } 453 | } 454 | 455 | fn register_message_type( 456 | settings: MessageChannelSettings, 457 | spawn: S, 458 | timer: T, 459 | packet_pool: P, 460 | multiplexer: &mut PacketMultiplexer, 461 | channels_map: &mut ChannelsMap, 462 | ) -> ChannelTask 463 | where 464 | S: Spawn + Clone + 'static, 465 | T: Timer + Clone + 'static, 466 | P: PacketPool + Clone + Send + 'static, 467 | P::Packet: Send, 468 | M: ChannelMessage, 469 | { 470 | let (incoming_sender, incoming_receiver) = spsc::channel::(settings.message_buffer_size); 471 | let (outgoing_sender, outgoing_receiver) = spsc::channel::(settings.message_buffer_size); 472 | 473 | let (flush_sender, flush_receiver) = event_watch::channel(); 474 | 475 | let (channel_sender, channel_receiver, statistics) = multiplexer 476 | .open_channel(settings.channel, settings.packet_buffer_size) 477 | .expect("duplicate packet channel"); 478 | 479 | let packet_pool = MuxPacketPool::new(packet_pool); 480 | 481 | let channel_task = match settings.channel_mode { 482 | MessageChannelMode::Unreliable(unreliable_settings) => channel_task( 483 | UnreliableTypedChannel::new(UnreliableChannel::new( 484 | timer, 485 | packet_pool, 486 | unreliable_settings, 487 | channel_sender, 488 | channel_receiver, 489 | )), 490 | incoming_sender, 491 | outgoing_receiver, 492 | flush_receiver, 493 | ) 494 | .boxed(), 495 | MessageChannelMode::Reliable(reliable_settings) => channel_task( 496 | ReliableTypedChannel::new(ReliableChannel::new( 497 | spawn, 498 | timer, 499 | packet_pool, 500 | reliable_settings, 501 | channel_sender, 502 | channel_receiver, 503 | )), 504 | incoming_sender, 505 | outgoing_receiver, 506 | flush_receiver, 507 | ) 508 | .boxed(), 509 | MessageChannelMode::Compressed(reliable_settings) => channel_task( 510 | CompressedTypedChannel::new(ReliableChannel::new( 511 | spawn, 512 | timer, 513 | packet_pool, 514 | reliable_settings, 515 | channel_sender, 516 | channel_receiver, 517 | )), 518 | incoming_sender, 519 | outgoing_receiver, 520 | flush_receiver, 521 | ) 522 | .boxed(), 523 | }; 524 | 525 | channels_map.insert(ChannelSet:: { 526 | outgoing_sender, 527 | flush_sender, 528 | incoming_receiver, 529 | statistics, 530 | }); 531 | 532 | channel_task 533 | } 534 | 535 | trait MessageBincodeChannel { 536 | fn poll_recv(&mut self, cx: &mut Context) -> Poll>; 537 | fn poll_send(&mut self, cx: &mut Context, msg: &M) -> Poll>; 538 | fn poll_flush(&mut self, cx: &mut Context) -> Poll>; 539 | } 540 | 541 | impl MessageBincodeChannel for UnreliableTypedChannel 542 | where 543 | T: Timer, 544 | P: PacketPool, 545 | M: ChannelMessage, 546 | { 547 | fn poll_recv(&mut self, cx: &mut Context) -> Poll> { 548 | UnreliableTypedChannel::poll_recv(self, cx).map_err(|e| e.into()) 549 | } 550 | 551 | fn poll_send(&mut self, cx: &mut Context, msg: &M) -> Poll> { 552 | ready!(self.poll_send_ready(cx))?; 553 | Poll::Ready(Ok(self.start_send(msg)?)) 554 | } 555 | 556 | fn poll_flush(&mut self, cx: &mut Context) -> Poll> { 557 | UnreliableTypedChannel::poll_flush(self, cx).map_err(|e| e.into()) 558 | } 559 | } 560 | 561 | impl MessageBincodeChannel for ReliableTypedChannel { 562 | fn poll_recv(&mut self, cx: &mut Context) -> Poll> { 563 | ReliableTypedChannel::poll_recv(self, cx).map_err(|e| e.into()) 564 | } 565 | 566 | fn poll_send(&mut self, cx: &mut Context, msg: &M) -> Poll> { 567 | ready!(self.poll_send_ready(cx))?; 568 | Poll::Ready(Ok(self.start_send(msg)?)) 569 | } 570 | 571 | fn poll_flush(&mut self, cx: &mut Context) -> Poll> { 572 | ReliableTypedChannel::poll_flush(self, cx).map_err(|e| e.into()) 573 | } 574 | } 575 | 576 | impl MessageBincodeChannel for CompressedTypedChannel { 577 | fn poll_recv(&mut self, cx: &mut Context) -> Poll> { 578 | CompressedTypedChannel::poll_recv(self, cx).map_err(|e| e.into()) 579 | } 580 | 581 | fn poll_send(&mut self, cx: &mut Context, msg: &M) -> Poll> { 582 | CompressedTypedChannel::poll_send(self, cx, msg).map_err(|e| e.into()) 583 | } 584 | 585 | fn poll_flush(&mut self, cx: &mut Context) -> Poll> { 586 | CompressedTypedChannel::poll_flush(self, cx).map_err(|e| e.into()) 587 | } 588 | } 589 | 590 | async fn channel_task( 591 | mut channel: impl MessageBincodeChannel, 592 | mut incoming_message_sender: spsc::Sender, 593 | mut outgoing_message_receiver: spsc::Receiver, 594 | mut flush_receiver: event_watch::Receiver, 595 | ) -> Result<(), TaskError> { 596 | enum Next { 597 | Incoming(M), 598 | Outgoing(M), 599 | Flush, 600 | } 601 | 602 | loop { 603 | let next = { 604 | select! { 605 | incoming = future::poll_fn(|cx| channel.poll_recv(cx)).fuse() => { 606 | Next::Incoming(incoming?) 607 | } 608 | outgoing = outgoing_message_receiver.next().fuse() => { 609 | Next::Outgoing(outgoing.ok_or(ChannelDisconnected)?) 610 | } 611 | _ = flush_receiver.wait().fuse() => Next::Flush, 612 | } 613 | }; 614 | 615 | match next { 616 | Next::Incoming(incoming) => incoming_message_sender.send(incoming).await?, 617 | Next::Outgoing(outgoing) => { 618 | future::poll_fn(|cx| channel.poll_send(cx, &outgoing)).await? 619 | } 620 | Next::Flush => loop { 621 | match outgoing_message_receiver.try_recv() { 622 | Ok(outgoing) => future::poll_fn(|cx| channel.poll_send(cx, &outgoing)).await?, 623 | Err(TryRecvError::Disconnected) => return Err(ChannelDisconnected.into()), 624 | Err(TryRecvError::Empty) => { 625 | future::poll_fn(|cx| channel.poll_flush(cx)).await?; 626 | break; 627 | } 628 | } 629 | }, 630 | } 631 | } 632 | } 633 | -------------------------------------------------------------------------------- /src/packet.rs: -------------------------------------------------------------------------------- 1 | use std::ops::{Deref, DerefMut}; 2 | 3 | /// The maximum usable packet size by `turbulence`. 4 | /// 5 | /// It is not useful for an implementation of `PacketPool` to return packets with larger capacity 6 | /// than this, `turbulence` may not be able to use the entire packet capacity otherwise. 7 | pub const MAX_PACKET_LEN: u16 = 32768; 8 | 9 | /// A trait for packet buffers used by `turbulence`. 10 | pub trait Packet: Deref + DerefMut { 11 | /// Resizes the packet to the given length, which must be at most the static capacity. 12 | fn resize(&mut self, len: usize, val: u8); 13 | 14 | fn extend(&mut self, other: &[u8]) { 15 | let cur_len = self.len(); 16 | let new_len = cur_len + other.len(); 17 | self.resize(new_len, 0); 18 | self[cur_len..new_len].copy_from_slice(other); 19 | } 20 | 21 | fn truncate(&mut self, len: usize) { 22 | let len = len.min(self.len()); 23 | self.resize(len, 0); 24 | } 25 | 26 | fn clear(&mut self) { 27 | self.resize(0, 0); 28 | } 29 | } 30 | 31 | /// Trait for packet allocation and pooling. 32 | /// 33 | /// All packets that are allocated from `turbulence` are allocated through this interface. 34 | /// 35 | /// Packets must implement the `Packet` trait and should all have the same capacity: the MTU for 36 | /// whatever the underlying transport is, up to `MAX_PACKET_LEN` in size. 37 | pub trait PacketPool { 38 | type Packet: Packet; 39 | 40 | /// Static maximum capacity packets returned by this pool. 41 | fn capacity(&self) -> usize; 42 | 43 | fn acquire(&mut self) -> Self::Packet; 44 | } 45 | -------------------------------------------------------------------------------- /src/packet_multiplexer.rs: -------------------------------------------------------------------------------- 1 | use std::{ 2 | collections::{hash_map, HashMap}, 3 | fmt, 4 | ops::{Deref, DerefMut}, 5 | pin::Pin, 6 | sync::{ 7 | atomic::{AtomicU64, Ordering}, 8 | Arc, 9 | }, 10 | task::{Context, Poll}, 11 | u8, 12 | }; 13 | 14 | use futures::{stream::SelectAll, Sink, SinkExt, Stream, StreamExt}; 15 | use rustc_hash::{FxHashMap, FxHashSet}; 16 | use thiserror::Error; 17 | 18 | use crate::{ 19 | packet::{Packet, PacketPool}, 20 | spsc, 21 | }; 22 | 23 | pub type PacketChannel = u8; 24 | 25 | /// A wrapper over a `Packet` that reserves the first byte for the channel. 26 | #[derive(Debug)] 27 | pub struct MuxPacket

(P); 28 | 29 | impl

Packet for MuxPacket

30 | where 31 | P: Packet, 32 | { 33 | fn resize(&mut self, len: usize, val: u8) { 34 | self.0.resize(len + 1, val); 35 | } 36 | 37 | fn extend(&mut self, other: &[u8]) { 38 | self.0.extend(other); 39 | } 40 | 41 | fn truncate(&mut self, len: usize) { 42 | self.0.truncate(len + 1); 43 | } 44 | 45 | fn clear(&mut self) { 46 | self.0.resize(1, 0); 47 | } 48 | } 49 | 50 | impl

Deref for MuxPacket

51 | where 52 | P: Packet, 53 | { 54 | type Target = [u8]; 55 | 56 | fn deref(&self) -> &[u8] { 57 | &self.0[1..] 58 | } 59 | } 60 | 61 | impl

DerefMut for MuxPacket

62 | where 63 | P: Packet, 64 | { 65 | fn deref_mut(&mut self) -> &mut [u8] { 66 | &mut self.0[1..] 67 | } 68 | } 69 | 70 | #[derive(Debug, Clone)] 71 | pub struct MuxPacketPool

(P); 72 | 73 | impl

MuxPacketPool

{ 74 | pub fn new(packet_pool: P) -> Self { 75 | MuxPacketPool(packet_pool) 76 | } 77 | } 78 | 79 | impl

PacketPool for MuxPacketPool

80 | where 81 | P: PacketPool, 82 | { 83 | type Packet = MuxPacket; 84 | 85 | fn capacity(&self) -> usize { 86 | self.0.capacity() - 1 87 | } 88 | 89 | fn acquire(&mut self) -> MuxPacket { 90 | let mut packet = self.0.acquire(); 91 | packet.resize(1, 0); 92 | MuxPacket(packet) 93 | } 94 | } 95 | 96 | impl

From

for MuxPacketPool

{ 97 | fn from(pool: P) -> MuxPacketPool

{ 98 | MuxPacketPool(pool) 99 | } 100 | } 101 | 102 | #[derive(Debug, Error)] 103 | #[error("packet channel has already been opened")] 104 | pub struct DuplicateChannel; 105 | 106 | #[derive(Debug, Copy, Clone)] 107 | pub struct ChannelTotals { 108 | pub packets: u64, 109 | pub bytes: u64, 110 | } 111 | 112 | #[derive(Debug, Clone)] 113 | pub struct ChannelStatistics(Arc); 114 | 115 | impl ChannelStatistics { 116 | pub fn incoming_totals(&self) -> ChannelTotals { 117 | ChannelTotals { 118 | packets: self.0.incoming_packets.load(Ordering::Relaxed), 119 | bytes: self.0.incoming_bytes.load(Ordering::Relaxed), 120 | } 121 | } 122 | 123 | pub fn outgoing_totals(&self) -> ChannelTotals { 124 | ChannelTotals { 125 | packets: self.0.outgoing_packets.load(Ordering::Relaxed), 126 | bytes: self.0.outgoing_bytes.load(Ordering::Relaxed), 127 | } 128 | } 129 | } 130 | 131 | /// Routes packets marked with a channel header from a single `Sink` / `Stream` pair to a set of 132 | /// `Sink` / `Stream` pairs for each channel. 133 | /// 134 | /// Also monitors bandwidth on each channel independently, and returns a `ChannelStatistics` handle 135 | /// to query bandwidth totals for that specific channel. 136 | pub struct PacketMultiplexer

{ 137 | incoming: HashMap>, 138 | outgoing: SelectAll>, 139 | } 140 | 141 | impl

PacketMultiplexer

142 | where 143 | P: Packet, 144 | { 145 | pub fn new() -> PacketMultiplexer

{ 146 | PacketMultiplexer { 147 | incoming: HashMap::new(), 148 | outgoing: SelectAll::new(), 149 | } 150 | } 151 | 152 | /// Open a multiplexed packet channel, producing a sender for outgoing `MuxPacket`s on this 153 | /// channel, and a receiver for incoming `MuxPacket`s on this channel. 154 | /// 155 | /// The `buffer_size` parameter controls the buffer size requested when creating the spsc 156 | /// channels for the returned `Sender` and `Receiver`. 157 | pub fn open_channel( 158 | &mut self, 159 | channel: PacketChannel, 160 | buffer_size: usize, 161 | ) -> Result< 162 | ( 163 | spsc::Sender>, 164 | spsc::Receiver>, 165 | ChannelStatistics, 166 | ), 167 | DuplicateChannel, 168 | > { 169 | let statistics = Arc::new(ChannelStatisticsData::default()); 170 | match self.incoming.entry(channel) { 171 | hash_map::Entry::Occupied(_) => Err(DuplicateChannel), 172 | hash_map::Entry::Vacant(vacant) => { 173 | let (incoming_sender, incoming_receiver) = spsc::channel(buffer_size); 174 | let (outgoing_sender, outgoing_receiver) = spsc::channel(buffer_size); 175 | vacant.insert(ChannelSender { 176 | sender: incoming_sender, 177 | statistics: Arc::clone(&statistics), 178 | }); 179 | self.outgoing.push(ChannelReceiver { 180 | channel, 181 | receiver: outgoing_receiver, 182 | statistics: Arc::clone(&statistics), 183 | }); 184 | Ok(( 185 | outgoing_sender, 186 | incoming_receiver, 187 | ChannelStatistics(statistics), 188 | )) 189 | } 190 | } 191 | } 192 | 193 | /// Start multiplexing packets to all opened channels. 194 | /// 195 | /// Returns an `IncomingMultiplexedPackets` which is a `Sink` for incoming packets, and an 196 | /// `OutgoingMultiplexedPackets` which is a `Stream` for outgoing packets. 197 | pub fn start(self) -> (IncomingMultiplexedPackets

, OutgoingMultiplexedPackets

) { 198 | ( 199 | IncomingMultiplexedPackets { 200 | incoming: self.incoming.into_iter().collect(), 201 | to_send: None, 202 | to_flush: FxHashSet::default(), 203 | }, 204 | OutgoingMultiplexedPackets { 205 | outgoing: self.outgoing, 206 | }, 207 | ) 208 | } 209 | } 210 | 211 | #[derive(Debug, Error)] 212 | pub enum IncomingError { 213 | #[error("packet received for unopened channel")] 214 | UnknownPacketChannel, 215 | #[error("channel receiver has been dropped")] 216 | ChannelReceiverDropped, 217 | } 218 | 219 | #[derive(Error)] 220 | pub enum IncomingTrySendError

{ 221 | #[error("packet channel is full")] 222 | IsFull(P), 223 | #[error(transparent)] 224 | Error(#[from] IncomingError), 225 | } 226 | 227 | impl

fmt::Debug for IncomingTrySendError

{ 228 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 229 | match self { 230 | IncomingTrySendError::IsFull(_) => write!(f, "IncomingTrySendError::IsFull"), 231 | IncomingTrySendError::Error(err) => f 232 | .debug_tuple("IncomingTrySendError::Error") 233 | .field(err) 234 | .finish(), 235 | } 236 | } 237 | } 238 | 239 | impl

IncomingTrySendError

{ 240 | pub fn is_full(&self) -> bool { 241 | match self { 242 | IncomingTrySendError::IsFull(_) => true, 243 | _ => false, 244 | } 245 | } 246 | } 247 | 248 | /// A handle to push incoming packets into the multiplexer. 249 | pub struct IncomingMultiplexedPackets

{ 250 | incoming: FxHashMap>, 251 | to_send: Option

, 252 | to_flush: FxHashSet, 253 | } 254 | 255 | impl

Unpin for IncomingMultiplexedPackets

{} 256 | 257 | impl

IncomingMultiplexedPackets

258 | where 259 | P: Packet, 260 | { 261 | /// Attempt to send the given packet to the appropriate multiplexed channel without blocking. 262 | /// 263 | /// If a normal error occurs, returns `IncomingError::Error`, if the destination channel buffer 264 | /// is full, returns `IncomingTrySendError::IsFull`. 265 | pub fn try_send(&mut self, packet: P) -> Result<(), IncomingTrySendError

> { 266 | let channel = packet[0]; 267 | let incoming = self 268 | .incoming 269 | .get_mut(&channel) 270 | .ok_or(IncomingError::UnknownPacketChannel)?; 271 | 272 | let mux_packet_len = (packet.len() - 1) as u64; 273 | incoming.sender.try_send(MuxPacket(packet)).map_err(|e| { 274 | if e.is_full() { 275 | IncomingTrySendError::IsFull(e.into_inner().0) 276 | } else { 277 | IncomingError::ChannelReceiverDropped.into() 278 | } 279 | })?; 280 | incoming.statistics.mark_incoming_packet(mux_packet_len); 281 | 282 | Ok(()) 283 | } 284 | } 285 | 286 | impl

Sink

for IncomingMultiplexedPackets

287 | where 288 | P: Packet, 289 | { 290 | type Error = IncomingError; 291 | 292 | fn poll_ready(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll> { 293 | if let Some(packet) = self.to_send.take() { 294 | let channel = packet[0]; 295 | let incoming = self 296 | .incoming 297 | .get_mut(&channel) 298 | .ok_or(IncomingError::UnknownPacketChannel)?; 299 | match incoming.sender.poll_ready_unpin(cx) { 300 | Poll::Pending => { 301 | self.to_send = Some(packet); 302 | Poll::Pending 303 | } 304 | Poll::Ready(Ok(())) => { 305 | let mux_packet_len = (packet.len() - 1) as u64; 306 | incoming 307 | .sender 308 | .start_send_unpin(MuxPacket(packet)) 309 | .map_err(|_| IncomingError::ChannelReceiverDropped)?; 310 | incoming.statistics.mark_incoming_packet(mux_packet_len); 311 | self.to_flush.insert(channel); 312 | Poll::Ready(Ok(())) 313 | } 314 | Poll::Ready(Err(_)) => Poll::Ready(Err(IncomingError::ChannelReceiverDropped)), 315 | } 316 | } else { 317 | Poll::Ready(Ok(())) 318 | } 319 | } 320 | 321 | fn start_send(mut self: Pin<&mut Self>, item: P) -> Result<(), Self::Error> { 322 | assert!(self.to_send.is_none()); 323 | self.to_send = Some(item); 324 | Ok(()) 325 | } 326 | 327 | fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll> { 328 | if self.as_mut().poll_ready(cx)?.is_pending() { 329 | return Poll::Pending; 330 | } 331 | while let Some(&channel) = self.to_flush.iter().next() { 332 | let incoming = self 333 | .incoming 334 | .get_mut(&channel) 335 | .ok_or(IncomingError::UnknownPacketChannel)?; 336 | if incoming 337 | .sender 338 | .poll_flush_unpin(cx) 339 | .map_err(|_| IncomingError::ChannelReceiverDropped)? 340 | .is_pending() 341 | { 342 | return Poll::Pending; 343 | } 344 | self.to_flush.remove(&channel); 345 | } 346 | Poll::Ready(Ok(())) 347 | } 348 | 349 | fn poll_close(self: Pin<&mut Self>, cx: &mut Context) -> Poll> { 350 | self.poll_flush(cx) 351 | } 352 | } 353 | 354 | /// A handle to receive outgoing packets from the multiplexer. 355 | pub struct OutgoingMultiplexedPackets

{ 356 | outgoing: SelectAll>, 357 | } 358 | 359 | impl

Stream for OutgoingMultiplexedPackets

360 | where 361 | P: Packet, 362 | { 363 | type Item = P; 364 | 365 | fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll> { 366 | self.outgoing.poll_next_unpin(cx) 367 | } 368 | } 369 | 370 | struct ChannelSender

{ 371 | sender: spsc::Sender>, 372 | statistics: Arc, 373 | } 374 | 375 | struct ChannelReceiver

{ 376 | channel: PacketChannel, 377 | receiver: spsc::Receiver>, 378 | statistics: Arc, 379 | } 380 | 381 | impl

Unpin for ChannelReceiver

{} 382 | 383 | impl

Stream for ChannelReceiver

384 | where 385 | P: Packet, 386 | { 387 | type Item = P; 388 | 389 | fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll> { 390 | match self.receiver.poll_next_unpin(cx) { 391 | Poll::Ready(Some(packet)) => { 392 | let mut packet = packet.0; 393 | packet[0] = self.channel; 394 | self.statistics 395 | .mark_outgoing_packet((packet.len() - 1) as u64); 396 | Poll::Ready(Some(packet)) 397 | } 398 | Poll::Ready(None) => Poll::Ready(None), 399 | Poll::Pending => Poll::Pending, 400 | } 401 | } 402 | } 403 | 404 | #[derive(Debug, Default)] 405 | struct ChannelStatisticsData { 406 | incoming_packets: AtomicU64, 407 | incoming_bytes: AtomicU64, 408 | 409 | outgoing_packets: AtomicU64, 410 | outgoing_bytes: AtomicU64, 411 | } 412 | 413 | impl ChannelStatisticsData { 414 | fn mark_incoming_packet(&self, len: u64) { 415 | self.incoming_packets.fetch_add(1, Ordering::Relaxed); 416 | self.incoming_bytes.fetch_add(len, Ordering::Relaxed); 417 | } 418 | 419 | fn mark_outgoing_packet(&self, len: u64) { 420 | self.outgoing_packets.fetch_add(1, Ordering::Relaxed); 421 | self.outgoing_bytes.fetch_add(len, Ordering::Relaxed); 422 | } 423 | } 424 | -------------------------------------------------------------------------------- /src/reliable_bincode_channel.rs: -------------------------------------------------------------------------------- 1 | use std::{ 2 | marker::PhantomData, 3 | task::{Context, Poll}, 4 | u16, 5 | }; 6 | 7 | use bincode::Options as _; 8 | use byteorder::{ByteOrder, LittleEndian}; 9 | use futures::{future, ready, task}; 10 | use serde::{Deserialize, Serialize}; 11 | use thiserror::Error; 12 | 13 | use crate::reliable_channel::{self, ReliableChannel}; 14 | 15 | /// The maximum serialized length of a `ReliableBincodeChannel` message. 16 | pub const MAX_MESSAGE_LEN: u16 = u16::MAX; 17 | 18 | #[derive(Debug, Error)] 19 | pub enum SendError { 20 | /// Fatal internal channel error. 21 | #[error("reliable channel error: {0}")] 22 | ReliableChannelError(#[from] reliable_channel::Error), 23 | /// Non-fatal error, message is unsent. 24 | #[error("bincode serialization error: {0}")] 25 | BincodeError(#[from] bincode::Error), 26 | } 27 | 28 | #[derive(Debug, Error)] 29 | pub enum RecvError { 30 | /// Fatal internal channel error. 31 | #[error("reliable channel error: {0}")] 32 | ReliableChannelError(#[from] reliable_channel::Error), 33 | /// Non-fatal error, message is skipped. 34 | #[error("bincode serialization error: {0}")] 35 | BincodeError(#[from] bincode::Error), 36 | } 37 | 38 | /// Wraps a `ReliableChannel` together with an internal buffer to allow easily sending message types 39 | /// serialized with `bincode`. 40 | /// 41 | /// Messages are guaranteed to arrive, and are guaranteed to be in order. Messages have a maximum 42 | /// length, but this maximum size can be larger than the size of an individual packet. 43 | pub struct ReliableBincodeChannel { 44 | channel: ReliableChannel, 45 | 46 | write_buffer: Vec, 47 | write_pos: usize, 48 | 49 | read_buffer: Vec, 50 | read_pos: usize, 51 | } 52 | 53 | impl From for ReliableBincodeChannel { 54 | fn from(channel: ReliableChannel) -> Self { 55 | Self::new(channel) 56 | } 57 | } 58 | 59 | impl ReliableBincodeChannel { 60 | /// Create a new `ReliableBincodeChannel` with a maximum message size of `max_message_len`. 61 | pub fn new(channel: ReliableChannel) -> Self { 62 | ReliableBincodeChannel { 63 | channel, 64 | write_buffer: Vec::new(), 65 | write_pos: 0, 66 | read_buffer: Vec::new(), 67 | read_pos: 0, 68 | } 69 | } 70 | 71 | pub fn into_inner(self) -> ReliableChannel { 72 | self.channel 73 | } 74 | 75 | /// Write the given message to the reliable channel. 76 | /// 77 | /// In order to ensure that messages are sent in a timely manner, `flush` must be called after 78 | /// calling this method. Without calling `flush`, any pending writes will not be sent until the 79 | /// next automatic sender task wakeup. 80 | /// 81 | /// This method is cancel safe, it will never partially send a message, and completes 82 | /// immediately upon successfully queuing a message to send. 83 | pub async fn send(&mut self, msg: &M) -> Result<(), SendError> { 84 | future::poll_fn(|cx| self.poll_send_ready(cx)).await?; 85 | self.start_send(msg)?; 86 | Ok(()) 87 | } 88 | 89 | pub fn try_send(&mut self, msg: &M) -> Result { 90 | if self.try_send_ready()? { 91 | self.start_send(msg)?; 92 | Ok(true) 93 | } else { 94 | Ok(false) 95 | } 96 | } 97 | 98 | /// Ensure that any previously sent messages are sent as soon as possible. 99 | /// 100 | /// This method is cancel safe. 101 | pub async fn flush(&mut self) -> Result<(), reliable_channel::Error> { 102 | future::poll_fn(|cx| self.poll_flush(cx)).await 103 | } 104 | 105 | pub fn try_flush(&mut self) -> Result { 106 | match self.poll_flush(&mut Context::from_waker(task::noop_waker_ref())) { 107 | Poll::Pending => Ok(false), 108 | Poll::Ready(Ok(())) => Ok(true), 109 | Poll::Ready(Err(err)) => Err(err), 110 | } 111 | } 112 | 113 | /// Read the next available incoming message. 114 | /// 115 | /// This method is cancel safe, it will never partially read a message or drop received 116 | /// messages. 117 | pub async fn recv<'a, M: Deserialize<'a>>(&'a mut self) -> Result { 118 | future::poll_fn(|cx| self.poll_recv_ready(cx)).await?; 119 | self.recv_next::() 120 | } 121 | 122 | pub fn try_recv<'a, M: Deserialize<'a>>(&'a mut self) -> Result, RecvError> { 123 | match self.poll_recv::(&mut Context::from_waker(task::noop_waker_ref())) { 124 | Poll::Pending => Ok(None), 125 | Poll::Ready(Ok(val)) => Ok(Some(val)), 126 | Poll::Ready(Err(err)) => Err(err), 127 | } 128 | } 129 | 130 | pub fn poll_send_ready( 131 | &mut self, 132 | cx: &mut Context, 133 | ) -> Poll> { 134 | while !self.write_buffer.is_empty() { 135 | let len = ready!(self 136 | .channel 137 | .poll_write(cx, &self.write_buffer[self.write_pos..]))?; 138 | self.write_pos += len; 139 | if self.write_pos == self.write_buffer.len() { 140 | self.write_pos = 0; 141 | self.write_buffer.clear(); 142 | } 143 | } 144 | Poll::Ready(Ok(())) 145 | } 146 | 147 | pub fn try_send_ready(&mut self) -> Result { 148 | match self.poll_send_ready(&mut Context::from_waker(task::noop_waker_ref())) { 149 | Poll::Pending => Ok(false), 150 | Poll::Ready(Ok(())) => Ok(true), 151 | Poll::Ready(Err(err)) => Err(err), 152 | } 153 | } 154 | 155 | pub fn start_send(&mut self, msg: &M) -> Result<(), bincode::Error> { 156 | assert!(self.write_buffer.is_empty()); 157 | self.write_buffer.resize(2, 0); 158 | let bincode_config = self.bincode_config(); 159 | bincode_config.serialize_into(&mut self.write_buffer, msg)?; 160 | let message_len = self.write_buffer.len() - 2; 161 | LittleEndian::write_u16( 162 | &mut self.write_buffer[0..2], 163 | message_len.try_into().unwrap(), 164 | ); 165 | Ok(()) 166 | } 167 | 168 | pub fn poll_flush(&mut self, cx: &mut Context) -> Poll> { 169 | ready!(self.poll_send_ready(cx))?; 170 | self.channel.flush()?; 171 | Poll::Ready(Ok(())) 172 | } 173 | 174 | pub fn poll_recv<'a, M: Deserialize<'a>>( 175 | &'a mut self, 176 | cx: &mut Context, 177 | ) -> Poll> { 178 | ready!(self.poll_recv_ready(cx))?; 179 | Poll::Ready(self.recv_next::()) 180 | } 181 | 182 | fn poll_recv_ready(&mut self, cx: &mut Context) -> Poll> { 183 | if self.read_pos < 2 { 184 | self.read_buffer.resize(2, 0); 185 | ready!(self.poll_finish_read(cx))?; 186 | } 187 | 188 | let message_len = LittleEndian::read_u16(&self.read_buffer[0..2]); 189 | self.read_buffer.resize(message_len as usize + 2, 0); 190 | ready!(self.poll_finish_read(cx))?; 191 | 192 | Poll::Ready(Ok(())) 193 | } 194 | 195 | fn recv_next<'a, M: Deserialize<'a>>(&'a mut self) -> Result { 196 | let bincode_config = self.bincode_config(); 197 | let res = bincode_config.deserialize(&self.read_buffer[2..]); 198 | self.read_pos = 0; 199 | Ok(res?) 200 | } 201 | 202 | fn poll_finish_read(&mut self, cx: &mut Context) -> Poll> { 203 | while self.read_pos < self.read_buffer.len() { 204 | let len = ready!(self 205 | .channel 206 | .poll_read(cx, &mut self.read_buffer[self.read_pos..]))?; 207 | self.read_pos += len; 208 | } 209 | Poll::Ready(Ok(())) 210 | } 211 | 212 | fn bincode_config(&self) -> impl bincode::Options + Copy { 213 | bincode::options().with_limit(MAX_MESSAGE_LEN as u64) 214 | } 215 | } 216 | 217 | /// Wrapper over an `ReliableBincodeChannel` that only allows a single message type. 218 | pub struct ReliableTypedChannel { 219 | channel: ReliableBincodeChannel, 220 | _phantom: PhantomData, 221 | } 222 | 223 | impl From for ReliableTypedChannel { 224 | fn from(channel: ReliableChannel) -> Self { 225 | Self::new(channel) 226 | } 227 | } 228 | 229 | impl ReliableTypedChannel { 230 | pub fn new(channel: ReliableChannel) -> Self { 231 | ReliableTypedChannel { 232 | channel: ReliableBincodeChannel::new(channel), 233 | _phantom: PhantomData, 234 | } 235 | } 236 | 237 | pub fn into_inner(self) -> ReliableChannel { 238 | self.channel.into_inner() 239 | } 240 | 241 | pub async fn flush(&mut self) -> Result<(), reliable_channel::Error> { 242 | self.channel.flush().await 243 | } 244 | 245 | pub fn try_flush(&mut self) -> Result { 246 | self.channel.try_flush() 247 | } 248 | 249 | pub fn poll_flush(&mut self, cx: &mut Context) -> Poll> { 250 | self.channel.poll_flush(cx) 251 | } 252 | 253 | pub fn poll_send_ready( 254 | &mut self, 255 | cx: &mut Context, 256 | ) -> Poll> { 257 | self.channel.poll_send_ready(cx) 258 | } 259 | 260 | pub fn try_send_ready(&mut self) -> Result { 261 | self.channel.try_send_ready() 262 | } 263 | } 264 | 265 | impl ReliableTypedChannel { 266 | pub async fn send(&mut self, msg: &M) -> Result<(), SendError> { 267 | self.channel.send(msg).await 268 | } 269 | 270 | pub fn try_send(&mut self, msg: &M) -> Result { 271 | self.channel.try_send(msg) 272 | } 273 | 274 | pub fn start_send(&mut self, msg: &M) -> Result<(), bincode::Error> { 275 | self.channel.start_send(msg) 276 | } 277 | } 278 | 279 | impl<'a, M: Deserialize<'a>> ReliableTypedChannel { 280 | pub async fn recv(&'a mut self) -> Result { 281 | self.channel.recv::().await 282 | } 283 | 284 | pub fn try_recv(&'a mut self) -> Result, RecvError> { 285 | self.channel.try_recv::() 286 | } 287 | 288 | pub fn poll_recv(&'a mut self, cx: &mut Context) -> Poll> { 289 | self.channel.poll_recv::(cx) 290 | } 291 | } 292 | -------------------------------------------------------------------------------- /src/reliable_channel.rs: -------------------------------------------------------------------------------- 1 | use std::{ 2 | i16, 3 | num::Wrapping, 4 | pin::Pin, 5 | sync::Arc, 6 | task::{Context, Poll}, 7 | time::Duration, 8 | u32, 9 | }; 10 | 11 | use byteorder::{ByteOrder, LittleEndian}; 12 | use futures::{ 13 | future::{self, Fuse, FusedFuture, RemoteHandle}, 14 | select, 15 | task::AtomicWaker, 16 | FutureExt, SinkExt, StreamExt, 17 | }; 18 | use rustc_hash::FxHashMap; 19 | use thiserror::Error; 20 | 21 | use crate::{ 22 | bandwidth_limiter::BandwidthLimiter, 23 | packet::{Packet, PacketPool}, 24 | runtime::{Spawn, Timer}, 25 | spsc, 26 | windows::{ 27 | stream_gt, AckResult, RecvWindow, RecvWindowReader, SendWindow, SendWindowWriter, StreamPos, 28 | }, 29 | }; 30 | 31 | /// All reliable channel errors are fatal. Once any error is returned all further reliable channel 32 | /// method calls will return `Err(Error::Shutdown)`. 33 | #[derive(Debug, Error)] 34 | pub enum Error { 35 | #[error("incoming or outgoing packet channel has been disconnected")] 36 | Disconnected, 37 | #[error("remote endpoint has violated the reliability protocol")] 38 | ProtocolError, 39 | #[error("an error has been encountered that has caused the channel to shutdown")] 40 | Shutdown, 41 | } 42 | 43 | #[derive(Debug, Clone, PartialEq)] 44 | pub struct Settings { 45 | /// The target outgoing bandwidth, in bytes / sec. 46 | /// 47 | /// This is the target bandwidth usage for all sent packets, not the target bandwidth for the 48 | /// actual underlying stream. Both sends and resends (but not currently acks) count against this 49 | /// bandwidth limit, so this is designed to limit the amount of traffic this channel produces. 50 | pub bandwidth: u32, 51 | /// The maximum amount of bandwidth credit that can accumulate. This is the maximum bytes that 52 | /// will be sent in a single burst. 53 | pub burst_bandwidth: u32, 54 | /// The size of the incoming ring buffer. 55 | pub recv_window_size: u32, 56 | /// The size of the outgoing ring buffer. 57 | pub send_window_size: u32, 58 | /// The sending side of a channel will always send a constant amount of bytes more than what 59 | /// it believes the remote's recv window actually is, to avoid stalling the connection. This 60 | /// controls the amount past the recv window which will be sent, and also the initial amount of 61 | /// data that will be sent when the connection starts up. 62 | pub init_send: u32, 63 | /// The transmission task for the channel will wake up at this rate to do resends, if not woken 64 | /// up to send other data. 65 | pub resend_time: Duration, 66 | /// The initial estimate for the RTT. 67 | pub initial_rtt: Duration, 68 | /// The maximum reasonable RTT which will be used as an upper bound for packet RTT values. 69 | pub max_rtt: Duration, 70 | /// The computed RTT for each received acknowledgment will be mixed with the RTT estimate by 71 | /// this factor. 72 | pub rtt_update_factor: f64, 73 | /// Resends will occur if an acknowledgment is not received within this multiplicative factor of 74 | /// the estimated RTT. 75 | pub rtt_resend_factor: f64, 76 | } 77 | 78 | /// Turns a stream of unreliable, unordered packets into a reliable in-order stream of data. 79 | pub struct ReliableChannel { 80 | send_window_writer: SendWindowWriter, 81 | recv_window_reader: RecvWindowReader, 82 | shared: Arc, 83 | task: Fuse>, 84 | } 85 | 86 | impl ReliableChannel { 87 | pub fn new( 88 | spawn: S, 89 | timer: T, 90 | packet_pool: P, 91 | settings: Settings, 92 | sender: spsc::Sender, 93 | receiver: spsc::Receiver, 94 | ) -> Self 95 | where 96 | S: Spawn + 'static, 97 | T: Timer + 'static, 98 | P: PacketPool + Send + 'static, 99 | P::Packet: Send, 100 | { 101 | assert!(settings.bandwidth != 0); 102 | assert!(settings.recv_window_size != 0); 103 | assert!(settings.recv_window_size != 0); 104 | assert!(settings.burst_bandwidth != 0); 105 | assert!(settings.init_send != 0); 106 | assert!(settings.rtt_update_factor > 0.); 107 | assert!(settings.rtt_resend_factor > 0.); 108 | 109 | let resend_timer = Box::pin(timer.sleep(settings.resend_time).fuse()); 110 | 111 | let (send_window, send_window_writer) = 112 | SendWindow::new(settings.send_window_size, Wrapping(0)); 113 | let (recv_window, recv_window_reader) = 114 | RecvWindow::new(settings.recv_window_size, Wrapping(0)); 115 | 116 | let shared = Arc::new(Shared::default()); 117 | 118 | let bandwidth_limiter = 119 | BandwidthLimiter::new(&timer, settings.bandwidth, settings.burst_bandwidth); 120 | let remote_recv_available = settings.init_send; 121 | let rtt_estimate = settings.initial_rtt.as_secs_f64(); 122 | 123 | let task = Task { 124 | settings, 125 | timer, 126 | packet_pool, 127 | sender, 128 | receiver, 129 | shared: shared.clone(), 130 | send_window, 131 | recv_window, 132 | resend_timer, 133 | remote_recv_available, 134 | unacked_ranges: FxHashMap::default(), 135 | rtt_estimate, 136 | bandwidth_limiter, 137 | }; 138 | let (remote, remote_handle) = 139 | { async move { task.main_loop().await.unwrap_err() } }.remote_handle(); 140 | 141 | spawn.spawn(remote); 142 | 143 | ReliableChannel { 144 | send_window_writer, 145 | recv_window_reader, 146 | shared, 147 | task: remote_handle.fuse(), 148 | } 149 | } 150 | 151 | /// Write the given data to the reliable channel and return once any nonzero amount of data has 152 | /// been written. 153 | /// 154 | /// In order to ensure that all data will be sent, `ReliableChannel::flush` must be called after 155 | /// any number of writes. 156 | /// 157 | /// This method is cancel safe, it completes immediately once any amount of data is written, 158 | /// dropping an incomplete future will have no effect. 159 | pub async fn write(&mut self, data: &[u8]) -> Result { 160 | future::poll_fn(|cx| self.poll_write(cx, data)).await 161 | } 162 | 163 | /// Ensure that any previously written data will be fully sent. 164 | /// 165 | /// Returns once the sending task has been notified to wake up and will send the written data 166 | /// promptly. Does *not* actually wait for outgoing packets to be sent before returning. 167 | pub fn flush(&mut self) -> Result<(), Error> { 168 | if self.task.is_terminated() { 169 | Err(Error::Shutdown) 170 | } else if let Some(error) = (&mut self.task).now_or_never() { 171 | Err(error) 172 | } else { 173 | self.shared.send_ready.wake(); 174 | Ok(()) 175 | } 176 | } 177 | 178 | /// Read any available data. Returns once at least one byte of data has been read. 179 | /// 180 | /// This method is cancel safe, it completes immediately once any amount of data is read, 181 | /// dropping an incomplete future will have no effect. 182 | pub async fn read(&mut self, data: &mut [u8]) -> Result { 183 | future::poll_fn(|cx| self.poll_read(cx, data)).await 184 | } 185 | 186 | pub fn poll_write(&mut self, cx: &mut Context, data: &[u8]) -> Poll> { 187 | if self.task.is_terminated() { 188 | return Poll::Ready(Err(Error::Shutdown)); 189 | } 190 | 191 | if let Poll::Ready(err) = self.task.poll_unpin(cx) { 192 | return Poll::Ready(Err(err)); 193 | } 194 | 195 | if data.is_empty() { 196 | return Poll::Ready(Ok(0)); 197 | } 198 | 199 | let len = self.send_window_writer.write(data); 200 | if len > 0 { 201 | Poll::Ready(Ok(len as usize)) 202 | } else { 203 | self.shared.write_ready.register(cx.waker()); 204 | let len = self.send_window_writer.write(data); 205 | if len > 0 { 206 | Poll::Ready(Ok(len as usize)) 207 | } else { 208 | self.shared.send_ready.wake(); 209 | Poll::Pending 210 | } 211 | } 212 | } 213 | 214 | pub fn poll_read(&mut self, cx: &mut Context, data: &mut [u8]) -> Poll> { 215 | if self.task.is_terminated() { 216 | return Poll::Ready(Err(Error::Shutdown)); 217 | } 218 | 219 | if let Poll::Ready(err) = self.task.poll_unpin(cx) { 220 | return Poll::Ready(Err(err)); 221 | } 222 | 223 | if data.is_empty() { 224 | return Poll::Ready(Ok(0)); 225 | } 226 | 227 | let len = self.recv_window_reader.read(data); 228 | if len > 0 { 229 | Poll::Ready(Ok(len as usize)) 230 | } else { 231 | self.shared.read_ready.register(cx.waker()); 232 | let len = self.recv_window_reader.read(data); 233 | if len > 0 { 234 | Poll::Ready(Ok(len as usize)) 235 | } else { 236 | Poll::Pending 237 | } 238 | } 239 | } 240 | 241 | /// The amount of space currently available for writing without blocking. 242 | pub fn write_available(&self) -> usize { 243 | self.send_window_writer.write_available() as usize 244 | } 245 | 246 | /// Attempt to write data without blocking or registering wakeups. 247 | pub fn try_write(&mut self, data: &[u8]) -> Result { 248 | if self.task.is_terminated() { 249 | Err(Error::Shutdown) 250 | } else { 251 | Ok(self.send_window_writer.write(data) as usize) 252 | } 253 | } 254 | 255 | /// Attempt to read data without blocking or registering wakeups. 256 | pub fn try_read(&mut self, data: &mut [u8]) -> Result { 257 | if self.task.is_terminated() { 258 | Err(Error::Shutdown) 259 | } else { 260 | Ok(self.recv_window_reader.read(data) as usize) 261 | } 262 | } 263 | } 264 | 265 | #[derive(Default)] 266 | struct Shared { 267 | send_ready: AtomicWaker, 268 | write_ready: AtomicWaker, 269 | read_ready: AtomicWaker, 270 | } 271 | 272 | struct UnackedRange { 273 | start: StreamPos, 274 | end: StreamPos, 275 | last_sent: Option, 276 | retransmit: bool, 277 | } 278 | 279 | struct Task 280 | where 281 | T: Timer, 282 | P: PacketPool, 283 | { 284 | timer: T, 285 | settings: Settings, 286 | packet_pool: P, 287 | sender: spsc::Sender, 288 | receiver: spsc::Receiver, 289 | 290 | shared: Arc, 291 | send_window: SendWindow, 292 | recv_window: RecvWindow, 293 | resend_timer: Pin>>, 294 | remote_recv_available: u32, 295 | unacked_ranges: FxHashMap>, 296 | rtt_estimate: f64, 297 | bandwidth_limiter: BandwidthLimiter, 298 | } 299 | 300 | impl Task 301 | where 302 | T: Timer, 303 | P: PacketPool, 304 | { 305 | async fn main_loop(mut self) -> Result<(), Error> { 306 | loop { 307 | enum WakeReason

{ 308 | ResendTimer, 309 | IncomingPacket(P), 310 | SendAvailable, 311 | } 312 | 313 | self.bandwidth_limiter.update_available(&self.timer); 314 | 315 | let wake_reason = { 316 | let bandwidth_limiter = &self.bandwidth_limiter; 317 | let resend_timer = &mut self.resend_timer; 318 | 319 | let resend_timer = async { 320 | if !resend_timer.is_terminated() { 321 | resend_timer.await; 322 | } 323 | // Don't bother waking up for the resend timer until we have bandwidth available 324 | // to do resends. 325 | if let Some(delay) = bandwidth_limiter.delay_until_available(&self.timer) { 326 | delay.await; 327 | } 328 | } 329 | .fuse(); 330 | 331 | let send_available = async { 332 | if self.remote_recv_available == 0 { 333 | // Don't wake up at all for sending new data if we couldn't send anything 334 | // anyway. 335 | future::pending::<()>().await; 336 | } 337 | 338 | // Don't wake up for sending new data until we have bandwidth available. 339 | if let Some(delay) = bandwidth_limiter.delay_until_available(&self.timer) { 340 | delay.await; 341 | } 342 | 343 | future::poll_fn(|cx| { 344 | if self.send_window.send_available() > 0 { 345 | Poll::Ready(()) 346 | } else { 347 | self.shared.send_ready.register(cx.waker()); 348 | if self.send_window.send_available() > 0 { 349 | Poll::Ready(()) 350 | } else { 351 | Poll::Pending 352 | } 353 | } 354 | }) 355 | .await 356 | } 357 | .fuse(); 358 | 359 | select! { 360 | _ = { resend_timer } => WakeReason::ResendTimer, 361 | incoming_packet = self.receiver.next().fuse() => { 362 | WakeReason::IncomingPacket(incoming_packet.ok_or(Error::Disconnected)?) 363 | }, 364 | _ = { send_available } => WakeReason::SendAvailable, 365 | } 366 | }; 367 | 368 | self.bandwidth_limiter.update_available(&self.timer); 369 | 370 | match wake_reason { 371 | WakeReason::ResendTimer => { 372 | self.resend().await?; 373 | self.resend_timer 374 | .set(self.timer.sleep(self.settings.resend_time).fuse()); 375 | } 376 | WakeReason::IncomingPacket(packet) => { 377 | self.recv_packet(packet).await?; 378 | } 379 | WakeReason::SendAvailable => { 380 | // We should use available bandwidth for resends before sending, to avoid 381 | // starving resends 382 | self.resend().await?; 383 | self.resend_timer 384 | .set(self.timer.sleep(self.settings.resend_time).fuse()); 385 | 386 | self.send().await?; 387 | } 388 | } 389 | 390 | // Don't let the connection stall. If we are now out of unacked ranges to resend and 391 | // we believe the remote has no recv left, we will receive no acknowledgments to let us 392 | // update the remote receive window. Keep sending a small amount of data past the remote 393 | // receive window, even if it is unacked, so that we are notified when the remote starts 394 | // processing data again. 395 | if self.unacked_ranges.is_empty() && self.remote_recv_available == 0 { 396 | self.remote_recv_available = self.settings.init_send; 397 | } 398 | } 399 | } 400 | 401 | // Send any data available to send, if we have the bandwidth for it 402 | async fn send(&mut self) -> Result<(), Error> { 403 | if !self.bandwidth_limiter.bytes_available() { 404 | return Ok(()); 405 | } 406 | 407 | let send_amt = (self.send_window.send_available()) 408 | .min(self.remote_recv_available) 409 | .min(i16::MAX as u32); 410 | 411 | if send_amt == 0 { 412 | return Ok(()); 413 | } 414 | 415 | let send_amt = send_amt.min((self.packet_pool.capacity() - 6) as u32); 416 | let mut packet = self.packet_pool.acquire(); 417 | 418 | packet.resize(6 + send_amt as usize, 0); 419 | 420 | let (start, end) = self.send_window.send(&mut packet[6..]).unwrap(); 421 | assert_eq!((end - start).0, send_amt); 422 | 423 | LittleEndian::write_i16(&mut packet[0..2], send_amt as i16); 424 | LittleEndian::write_u32(&mut packet[2..6], start.0); 425 | 426 | self.unacked_ranges.insert( 427 | start, 428 | UnackedRange { 429 | start, 430 | end, 431 | last_sent: Some(self.timer.now()), 432 | retransmit: false, 433 | }, 434 | ); 435 | 436 | self.bandwidth_limiter.take_bytes(packet.len() as u32); 437 | self.sender 438 | .send(packet) 439 | .await 440 | .map_err(|_| Error::Disconnected)?; 441 | 442 | self.remote_recv_available -= send_amt; 443 | 444 | Ok(()) 445 | } 446 | 447 | // Resend any data whose retransmit time has been reached, if we have the bandwidth for it 448 | async fn resend(&mut self) -> Result<(), Error> { 449 | for unacked in self.unacked_ranges.values_mut() { 450 | if !self.bandwidth_limiter.bytes_available() { 451 | break; 452 | } 453 | 454 | let resend = if let Some(last_sent) = unacked.last_sent { 455 | let elapsed = self.timer.duration_between(last_sent, self.timer.now()); 456 | elapsed.as_secs_f64() > self.rtt_estimate * self.settings.rtt_resend_factor 457 | } else { 458 | true 459 | }; 460 | 461 | if resend { 462 | unacked.last_sent = Some(self.timer.now()); 463 | unacked.retransmit = true; 464 | 465 | let len = (unacked.end - unacked.start).0; 466 | 467 | let mut packet = self.packet_pool.acquire(); 468 | packet.resize(6 + len as usize, 0); 469 | LittleEndian::write_i16(&mut packet[0..2], len as i16); 470 | LittleEndian::write_u32(&mut packet[2..6], unacked.start.0); 471 | 472 | self.send_window 473 | .get_unacked(unacked.start, &mut packet[6..]); 474 | 475 | self.bandwidth_limiter.take_bytes(packet.len() as u32); 476 | 477 | self.sender 478 | .send(packet) 479 | .await 480 | .map_err(|_| Error::Disconnected)?; 481 | } 482 | } 483 | 484 | Ok(()) 485 | } 486 | 487 | // Receive the given packet and respond with an acknowledgment packet, ignoring bandwidth 488 | // limits. 489 | async fn recv_packet(&mut self, packet: P::Packet) -> Result<(), Error> { 490 | if packet.len() < 2 { 491 | return Err(Error::ProtocolError); 492 | } 493 | 494 | let data_len = LittleEndian::read_i16(&packet[0..2]); 495 | if data_len < 0 { 496 | if packet.len() != 10 { 497 | return Err(Error::ProtocolError); 498 | } 499 | 500 | let start_pos = Wrapping(LittleEndian::read_u32(&packet[2..6])); 501 | let end_pos = start_pos + Wrapping(-data_len as u32); 502 | let recv_window_end = Wrapping(LittleEndian::read_u32(&packet[6..10])); 503 | 504 | if stream_gt(recv_window_end, self.send_window.send_pos()) { 505 | let old_remote_recv_available = self.remote_recv_available; 506 | self.remote_recv_available = self 507 | .remote_recv_available 508 | .max((recv_window_end - self.send_window.send_pos()).0); 509 | 510 | if self.remote_recv_available != 0 && old_remote_recv_available == 0 { 511 | // If we now believe the remote is newly ready to receive data, go ahead and 512 | // send it. 513 | self.send().await?; 514 | } 515 | } 516 | 517 | let acked_range = match self.send_window.ack_range(start_pos, end_pos) { 518 | AckResult::NotFound => None, 519 | AckResult::Ack => { 520 | let acked = self.unacked_ranges.remove(&start_pos).unwrap(); 521 | assert_eq!(acked.end, end_pos); 522 | Some(acked) 523 | } 524 | AckResult::PartialAck(nacked_end) => { 525 | let mut acked = self.unacked_ranges.remove(&start_pos).unwrap(); 526 | assert_eq!(acked.end, nacked_end); 527 | acked.end = end_pos; 528 | self.unacked_ranges.insert( 529 | end_pos, 530 | UnackedRange { 531 | start: end_pos, 532 | end: nacked_end, 533 | last_sent: None, 534 | retransmit: true, 535 | }, 536 | ); 537 | Some(acked) 538 | } 539 | }; 540 | 541 | if let Some(acked_range) = acked_range { 542 | // Only update the RTT estimation for acked ranges that did not need to be 543 | // retransmitted, otherwise we do not know which packet is being acked and thus 544 | // can't be sure of the actual RTT for this ack. 545 | if !acked_range.retransmit { 546 | if let Some(last_sent) = acked_range.last_sent { 547 | let rtt = self 548 | .timer 549 | .duration_between(last_sent, self.timer.now()) 550 | .min(self.settings.max_rtt) 551 | .as_secs_f64(); 552 | self.rtt_estimate += 553 | (rtt - self.rtt_estimate) * self.settings.rtt_update_factor; 554 | } 555 | } 556 | 557 | if self.send_window.write_available() > 0 { 558 | self.shared.write_ready.wake(); 559 | } 560 | } 561 | } else { 562 | if packet.len() < 6 { 563 | return Err(Error::ProtocolError); 564 | } 565 | 566 | let start_pos = Wrapping(LittleEndian::read_u32(&packet[2..6])); 567 | if data_len as usize != packet.len() - 6 { 568 | return Err(Error::ProtocolError); 569 | } 570 | 571 | if let Some(end_pos) = self.recv_window.recv(start_pos, &packet[6..]) { 572 | let mut ack_packet = self.packet_pool.acquire(); 573 | ack_packet.resize(10, 0); 574 | let ack_len = (end_pos - start_pos).0 as i16; 575 | LittleEndian::write_i16(&mut ack_packet[0..2], -ack_len); 576 | LittleEndian::write_u32(&mut ack_packet[2..6], start_pos.0); 577 | LittleEndian::write_u32(&mut ack_packet[6..10], self.recv_window.window_end().0); 578 | 579 | // We currently do not count acknowledgement packets against the outgoing bandwidth 580 | // at all. 581 | self.sender 582 | .send(ack_packet) 583 | .await 584 | .map_err(|_| Error::Disconnected)?; 585 | 586 | if self.recv_window.read_available() > 0 { 587 | self.shared.read_ready.wake(); 588 | } 589 | } 590 | } 591 | 592 | Ok(()) 593 | } 594 | } 595 | -------------------------------------------------------------------------------- /src/ring_buffer.rs: -------------------------------------------------------------------------------- 1 | use std::{ 2 | alloc::{alloc, dealloc, Layout}, 3 | mem::{self, MaybeUninit}, 4 | ptr::NonNull, 5 | slice, 6 | sync::{ 7 | atomic::{AtomicUsize, Ordering}, 8 | Arc, 9 | }, 10 | }; 11 | 12 | use cache_padded::CachePadded; 13 | 14 | pub struct RingBuffer { 15 | buffer: NonNull>, 16 | capacity: usize, 17 | head: CachePadded, 18 | tail: CachePadded, 19 | } 20 | 21 | impl RingBuffer { 22 | pub fn new(capacity: usize) -> (Writer, Reader) { 23 | assert!(capacity != 0); 24 | let buffer = Arc::new(Self { 25 | buffer: unsafe { 26 | NonNull::new(alloc(Layout::array::>(capacity).unwrap()) 27 | as *mut MaybeUninit) 28 | .unwrap() 29 | }, 30 | capacity, 31 | head: CachePadded::new(AtomicUsize::new(0)), 32 | tail: CachePadded::new(AtomicUsize::new(0)), 33 | }); 34 | 35 | let writer = Writer(buffer.clone()); 36 | let reader = Reader(buffer); 37 | (writer, reader) 38 | } 39 | 40 | pub fn write_available(&self) -> usize { 41 | let head = self.head.load(Ordering::Acquire); 42 | let tail = self.tail.load(Ordering::Acquire); 43 | 44 | head_to_tail(self.capacity, head, tail) 45 | } 46 | 47 | pub fn read_available(&self) -> usize { 48 | let head = self.head.load(Ordering::Acquire); 49 | let tail = self.tail.load(Ordering::Acquire); 50 | 51 | tail_to_head(self.capacity, tail, head) 52 | } 53 | } 54 | 55 | impl Drop for RingBuffer { 56 | fn drop(&mut self) { 57 | unsafe { 58 | dealloc( 59 | self.buffer.as_ptr() as *mut u8, 60 | Layout::array::>(self.capacity).unwrap(), 61 | ); 62 | } 63 | } 64 | } 65 | 66 | unsafe impl Send for RingBuffer {} 67 | unsafe impl Sync for RingBuffer {} 68 | 69 | pub struct Writer(Arc); 70 | 71 | impl Writer { 72 | pub fn available(&self) -> usize { 73 | self.0.write_available() 74 | } 75 | 76 | pub fn write(&mut self, mut offset: usize, mut data: &[u8]) -> usize { 77 | let head_pos = self.0.head.load(Ordering::Acquire); 78 | let tail_pos = self.0.tail.load(Ordering::Acquire); 79 | 80 | let head = collapse_position(self.0.capacity, head_pos); 81 | let tail = collapse_position(self.0.capacity, tail_pos); 82 | 83 | if head == tail && head_pos != tail_pos { 84 | return 0; 85 | } 86 | 87 | let (mut left, mut right): (&mut [MaybeUninit], &mut [MaybeUninit]) = unsafe { 88 | if head < tail { 89 | ( 90 | slice::from_raw_parts_mut(self.0.buffer.as_ptr().add(head), tail - head), 91 | &mut [], 92 | ) 93 | } else { 94 | ( 95 | slice::from_raw_parts_mut( 96 | self.0.buffer.as_ptr().add(head), 97 | self.0.capacity - head, 98 | ), 99 | slice::from_raw_parts_mut(self.0.buffer.as_ptr(), tail), 100 | ) 101 | } 102 | }; 103 | 104 | let left_eat = left.len().min(offset); 105 | left = &mut left[left_eat..]; 106 | offset -= left_eat; 107 | 108 | let left_len = left.len().min(data.len()); 109 | write_slice(&mut left[0..left_len], &data[0..left_len]); 110 | data = &data[left_len..]; 111 | 112 | let right_eat = right.len().min(offset); 113 | right = &mut right[right_eat..]; 114 | 115 | let right_len = right.len().min(data.len()); 116 | write_slice(&mut right[0..right_len], &data[0..right_len]); 117 | 118 | left_len + right_len 119 | } 120 | 121 | pub fn advance(&mut self, offset: usize) -> usize { 122 | let head = self.0.head.load(Ordering::Acquire); 123 | let tail = self.0.tail.load(Ordering::Acquire); 124 | 125 | let offset = offset.min(head_to_tail(self.0.capacity, head, tail)); 126 | let head = increment(self.0.capacity, head, offset); 127 | self.0.head.store(head, Ordering::Release); 128 | 129 | offset 130 | } 131 | 132 | pub fn buffer(&self) -> &RingBuffer { 133 | &self.0 134 | } 135 | } 136 | 137 | pub struct Reader(Arc); 138 | 139 | impl Reader { 140 | pub fn available(&self) -> usize { 141 | self.0.read_available() 142 | } 143 | 144 | pub fn read(&self, mut offset: usize, mut data: &mut [u8]) -> usize { 145 | let head_pos = self.0.head.load(Ordering::Acquire); 146 | let tail_pos = self.0.tail.load(Ordering::Acquire); 147 | 148 | let head = collapse_position(self.0.capacity, head_pos); 149 | let tail = collapse_position(self.0.capacity, tail_pos); 150 | 151 | if head == tail && head_pos == tail_pos { 152 | return 0; 153 | } 154 | 155 | let (mut left, mut right): (&[u8], &[u8]) = unsafe { 156 | if tail < head { 157 | ( 158 | slice::from_raw_parts(self.0.buffer.as_ptr().add(tail) as *mut u8, head - tail), 159 | &mut [], 160 | ) 161 | } else { 162 | ( 163 | slice::from_raw_parts( 164 | self.0.buffer.as_ptr().add(tail) as *mut u8, 165 | self.0.capacity - tail, 166 | ), 167 | slice::from_raw_parts(self.0.buffer.as_ptr() as *mut u8, head), 168 | ) 169 | } 170 | }; 171 | 172 | let left_eat = left.len().min(offset); 173 | left = &left[left_eat..]; 174 | offset -= left_eat; 175 | 176 | let left_len = left.len().min(data.len()); 177 | data[0..left_len].copy_from_slice(&left[0..left_len]); 178 | data = &mut data[left_len..]; 179 | 180 | let right_eat = right.len().min(offset); 181 | right = &right[right_eat..]; 182 | 183 | let right_len = right.len().min(data.len()); 184 | data[0..right_len].copy_from_slice(&right[0..right_len]); 185 | 186 | left_len + right_len 187 | } 188 | 189 | pub fn advance(&mut self, offset: usize) -> usize { 190 | let head = self.0.head.load(Ordering::Acquire); 191 | let tail = self.0.tail.load(Ordering::Acquire); 192 | 193 | let offset = offset.min(tail_to_head(self.0.capacity, tail, head)); 194 | let tail = increment(self.0.capacity, tail, offset); 195 | self.0.tail.store(tail, Ordering::Release); 196 | 197 | offset 198 | } 199 | 200 | pub fn buffer(&self) -> &RingBuffer { 201 | &self.0 202 | } 203 | } 204 | 205 | fn collapse_position(capacity: usize, pos: usize) -> usize { 206 | if pos < capacity { 207 | pos 208 | } else { 209 | pos - capacity 210 | } 211 | } 212 | 213 | fn tail_to_head(capacity: usize, tail: usize, head: usize) -> usize { 214 | if tail <= head { 215 | head - tail 216 | } else { 217 | capacity - (tail - capacity) + head 218 | } 219 | } 220 | 221 | fn head_to_tail(capacity: usize, head: usize, tail: usize) -> usize { 222 | capacity - tail_to_head(capacity, tail, head) 223 | } 224 | 225 | fn increment(capacity: usize, pos: usize, n: usize) -> usize { 226 | if n == 0 { 227 | return pos; 228 | } 229 | 230 | let threshold = (capacity - n) + capacity; 231 | if pos < threshold { 232 | pos + n 233 | } else { 234 | pos - threshold 235 | } 236 | } 237 | 238 | fn write_slice(dst: &mut [MaybeUninit], src: &[u8]) { 239 | let src: &[MaybeUninit] = unsafe { mem::transmute(src) }; 240 | dst.copy_from_slice(src); 241 | } 242 | 243 | #[cfg(test)] 244 | mod tests { 245 | use std::thread; 246 | 247 | use super::*; 248 | 249 | #[test] 250 | fn basic_read_write() { 251 | let (mut writer, mut reader) = RingBuffer::new(7); 252 | let mut buffer = [0; 7]; 253 | 254 | assert_eq!(writer.available(), 7); 255 | assert_eq!(writer.write(0, &[0, 1, 2]), 3); 256 | assert_eq!(writer.advance(3), 3); 257 | assert_eq!(writer.available(), 4); 258 | assert_eq!(reader.available(), 3); 259 | assert_eq!(reader.read(0, &mut buffer), 3); 260 | assert_eq!(buffer[0..3], [0, 1, 2]); 261 | assert_eq!(writer.available(), 4); 262 | assert_eq!(reader.advance(3), 3); 263 | assert_eq!(writer.available(), 7); 264 | assert_eq!(reader.available(), 0); 265 | assert_eq!(writer.write(0, &[0, 1, 2]), 3); 266 | assert_eq!(writer.advance(3), 3); 267 | assert_eq!(writer.available(), 4); 268 | assert_eq!(reader.read(0, &mut buffer[0..3]), 3); 269 | assert_eq!(buffer[0..3], [0, 1, 2]); 270 | assert_eq!(writer.write(0, &[3, 4, 5]), 3); 271 | assert_eq!(writer.advance(3), 3); 272 | assert_eq!(writer.available(), 1); 273 | assert_eq!(writer.write(0, &[6, 7, 8, 9]), 1); 274 | assert_eq!(writer.advance(1), 1); 275 | assert_eq!(writer.available(), 0); 276 | assert_eq!(reader.available(), 7); 277 | assert_eq!(reader.read(4, &mut buffer[0..5]), 3); 278 | assert_eq!(buffer[0..3], [4, 5, 6]); 279 | assert_eq!(reader.read(0, &mut buffer[0..2]), 2); 280 | assert_eq!(buffer[0..2], [0, 1]); 281 | assert_eq!(reader.advance(2), 2); 282 | assert_eq!(reader.available(), 5); 283 | assert_eq!(writer.available(), 2); 284 | assert_eq!(reader.read(0, &mut buffer[0..3]), 3); 285 | assert_eq!(buffer[0..3], [2, 3, 4]); 286 | assert_eq!(reader.advance(3), 3); 287 | assert_eq!(reader.available(), 2); 288 | assert_eq!(writer.available(), 5); 289 | assert_eq!(reader.read(0, &mut buffer[0..5]), 2); 290 | assert_eq!(buffer[0..2], [5, 6]); 291 | assert_eq!(reader.available(), 2); 292 | assert_eq!(writer.available(), 5); 293 | assert_eq!(reader.advance(5), 2); 294 | assert_eq!(reader.available(), 0); 295 | assert_eq!(writer.available(), 7); 296 | assert_eq!(writer.write(3, &[13, 14]), 2); 297 | assert_eq!(writer.write(0, &[10, 11, 12]), 3); 298 | assert_eq!(writer.advance(5), 5); 299 | assert_eq!(writer.available(), 2); 300 | assert_eq!(reader.available(), 5); 301 | assert_eq!(reader.read(2, &mut buffer[0..5]), 3); 302 | assert_eq!(buffer[0..3], [12, 13, 14]); 303 | assert_eq!(reader.read(0, &mut buffer[0..3]), 3); 304 | assert_eq!(buffer[0..3], [10, 11, 12]); 305 | } 306 | 307 | #[test] 308 | fn threaded_read_write() { 309 | let (mut writer, mut reader) = RingBuffer::new(64); 310 | 311 | let a = thread::spawn(move || { 312 | let mut b = [0; 32]; 313 | let mut i = 0; 314 | loop { 315 | let write = 11 + (i % 17); 316 | for j in 0..write { 317 | b[j] = ((i + j) % 256) as u8; 318 | } 319 | let len = writer.write(0, &b[0..write]); 320 | writer.advance(len); 321 | i += len; 322 | if i >= 10_000 { 323 | break; 324 | } 325 | } 326 | }); 327 | 328 | let b = thread::spawn(move || { 329 | let mut b = [0; 32]; 330 | let mut i = 0; 331 | loop { 332 | let r = reader.read(0, &mut b); 333 | for j in 0..r { 334 | assert_eq!(b[j], ((i + j) % 256) as u8); 335 | } 336 | assert_eq!(reader.advance(r), r); 337 | i += r; 338 | if i >= 10_000 { 339 | break; 340 | } 341 | } 342 | }); 343 | 344 | b.join().unwrap(); 345 | a.join().unwrap(); 346 | } 347 | } 348 | -------------------------------------------------------------------------------- /src/runtime.rs: -------------------------------------------------------------------------------- 1 | //! Traits for async runtime functionality needed by `turbulence`. 2 | 3 | use std::{future::Future, time::Duration}; 4 | 5 | /// This is similar to the `futures::task::Spawn` trait, but it is generic in the spawned 6 | /// future, which is better for backends like tokio. 7 | pub trait Spawn: Send + Sync { 8 | fn spawn(&self, future: F) 9 | where 10 | F: Future + Send + 'static; 11 | } 12 | 13 | /// This is designed so that it can be implemented on multiple platforms with multiple runtimes, 14 | /// including `wasm32-unknown-unknown`, where `std::time::Instant` is unavailable. 15 | pub trait Timer: Send + Sync { 16 | type Instant: Send + Sync + Copy; 17 | type Sleep: Future + Send; 18 | 19 | /// Return the current instant. 20 | fn now(&self) -> Self::Instant; 21 | 22 | /// Similarly to `std::time::Instant::duration_since`, may panic if `later` comes before 23 | /// `earlier`. 24 | fn duration_between(&self, earlier: Self::Instant, later: Self::Instant) -> Duration; 25 | 26 | /// Create a future which resolves after the given time has passed. 27 | fn sleep(&self, duration: Duration) -> Self::Sleep; 28 | } 29 | -------------------------------------------------------------------------------- /src/spsc.rs: -------------------------------------------------------------------------------- 1 | use std::{ 2 | pin::Pin, 3 | sync::Arc, 4 | task::{Context, Poll}, 5 | }; 6 | 7 | pub use crossbeam_channel::{TryRecvError, TrySendError}; 8 | use futures::{task::AtomicWaker, Sink, Stream}; 9 | use thiserror::Error; 10 | 11 | #[derive(Default)] 12 | struct Shared { 13 | send_ready: AtomicWaker, 14 | recv_ready: AtomicWaker, 15 | } 16 | 17 | pub struct Receiver { 18 | channel: crossbeam_channel::Receiver, 19 | shared: Arc, 20 | } 21 | 22 | impl Drop for Receiver { 23 | fn drop(&mut self) { 24 | self.shared.send_ready.wake(); 25 | } 26 | } 27 | 28 | impl Unpin for Receiver {} 29 | 30 | impl Stream for Receiver { 31 | type Item = T; 32 | 33 | fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll> { 34 | match self.try_recv() { 35 | Ok(r) => Poll::Ready(Some(r)), 36 | Err(TryRecvError::Disconnected) => Poll::Ready(None), 37 | Err(TryRecvError::Empty) => { 38 | self.shared.recv_ready.register(cx.waker()); 39 | match self.try_recv() { 40 | Ok(r) => Poll::Ready(Some(r)), 41 | Err(TryRecvError::Disconnected) => Poll::Ready(None), 42 | Err(TryRecvError::Empty) => Poll::Pending, 43 | } 44 | } 45 | } 46 | } 47 | } 48 | 49 | impl Receiver { 50 | pub fn try_recv(&mut self) -> Result { 51 | let t = self.channel.try_recv()?; 52 | self.shared.send_ready.wake(); 53 | Ok(t) 54 | } 55 | } 56 | 57 | #[derive(Debug, Error)] 58 | #[error("spsc channel disconnected")] 59 | pub struct Disconnected; 60 | 61 | pub struct Sender { 62 | channel: crossbeam_channel::Sender, 63 | shared: Arc, 64 | slot: Option, 65 | } 66 | 67 | impl Drop for Sender { 68 | fn drop(&mut self) { 69 | self.shared.recv_ready.wake() 70 | } 71 | } 72 | 73 | impl Unpin for Sender {} 74 | 75 | impl Sink for Sender { 76 | type Error = Disconnected; 77 | 78 | fn poll_ready(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll> { 79 | if let Some(t) = self.slot.take() { 80 | match self.try_send(t) { 81 | Ok(()) => Poll::Ready(Ok(())), 82 | Err(TrySendError::Disconnected(_)) => Poll::Ready(Err(Disconnected)), 83 | Err(TrySendError::Full(t)) => { 84 | self.shared.send_ready.register(cx.waker()); 85 | match self.try_send(t) { 86 | Ok(()) => Poll::Ready(Ok(())), 87 | Err(TrySendError::Disconnected(_)) => Poll::Ready(Err(Disconnected)), 88 | Err(TrySendError::Full(t)) => { 89 | self.slot = Some(t); 90 | Poll::Pending 91 | } 92 | } 93 | } 94 | } 95 | } else { 96 | Poll::Ready(Ok(())) 97 | } 98 | } 99 | 100 | fn start_send(mut self: Pin<&mut Self>, item: T) -> Result<(), Self::Error> { 101 | if self.slot.replace(item).is_some() { 102 | panic!("start_send called without without being ready"); 103 | } 104 | Ok(()) 105 | } 106 | 107 | fn poll_flush(self: Pin<&mut Self>, cx: &mut Context) -> Poll> { 108 | self.poll_ready(cx) 109 | } 110 | 111 | fn poll_close(self: Pin<&mut Self>, cx: &mut Context) -> Poll> { 112 | self.poll_flush(cx) 113 | } 114 | } 115 | 116 | impl Sender { 117 | pub fn try_send(&mut self, t: T) -> Result<(), TrySendError> { 118 | if let Some(prev) = self.slot.take() { 119 | if let Err(err) = self.channel.try_send(prev) { 120 | match err { 121 | TrySendError::Full(inner) => { 122 | self.slot = Some(inner); 123 | return Err(TrySendError::Full(t)); 124 | } 125 | TrySendError::Disconnected(inner) => { 126 | self.slot = Some(inner); 127 | return Err(TrySendError::Disconnected(t)); 128 | } 129 | } 130 | } else { 131 | self.shared.recv_ready.wake(); 132 | } 133 | } 134 | self.channel.try_send(t)?; 135 | self.shared.recv_ready.wake(); 136 | Ok(()) 137 | } 138 | } 139 | 140 | pub fn channel(capacity: usize) -> (Sender, Receiver) { 141 | let (sender, receiver) = crossbeam_channel::bounded(capacity); 142 | let shared = Arc::new(Shared::default()); 143 | 144 | ( 145 | Sender { 146 | channel: sender, 147 | shared: shared.clone(), 148 | slot: None, 149 | }, 150 | Receiver { 151 | channel: receiver, 152 | shared, 153 | }, 154 | ) 155 | } 156 | -------------------------------------------------------------------------------- /src/unreliable_bincode_channel.rs: -------------------------------------------------------------------------------- 1 | use std::{ 2 | marker::PhantomData, 3 | task::{Context, Poll}, 4 | }; 5 | 6 | use bincode::Options as _; 7 | use futures::{future, ready, task}; 8 | use serde::{Deserialize, Serialize}; 9 | use thiserror::Error; 10 | 11 | use crate::{ 12 | packet::PacketPool, 13 | runtime::Timer, 14 | unreliable_channel::{self, UnreliableChannel}, 15 | }; 16 | 17 | #[derive(Debug, Error)] 18 | pub enum SendError { 19 | #[error("unreliable channel error: {0}")] 20 | UnreliableChannelError(#[from] unreliable_channel::SendError), 21 | /// Non-fatal error, message is unsent. 22 | #[error("bincode serialization error: {0}")] 23 | BincodeError(#[from] bincode::Error), 24 | } 25 | 26 | #[derive(Debug, Error)] 27 | pub enum RecvError { 28 | #[error("unreliable channel error: {0}")] 29 | UnreliableChannelError(#[from] unreliable_channel::RecvError), 30 | /// Non-fatal error, message is skipped. 31 | #[error("bincode serialization error: {0}")] 32 | BincodeError(#[from] bincode::Error), 33 | } 34 | 35 | /// Wraps an `UnreliableChannel` together with an internal buffer to allow easily sending message 36 | /// types serialized with `bincode`. 37 | /// 38 | /// Just like the underlying channel, messages are not guaranteed to arrive, nor are they guaranteed 39 | /// to arrive in order. 40 | pub struct UnreliableBincodeChannel 41 | where 42 | T: Timer, 43 | P: PacketPool, 44 | { 45 | channel: UnreliableChannel, 46 | pending_write: Vec, 47 | } 48 | 49 | impl From> for UnreliableBincodeChannel 50 | where 51 | T: Timer, 52 | P: PacketPool, 53 | { 54 | fn from(channel: UnreliableChannel) -> Self { 55 | Self::new(channel) 56 | } 57 | } 58 | 59 | impl UnreliableBincodeChannel 60 | where 61 | T: Timer, 62 | P: PacketPool, 63 | { 64 | pub fn new(channel: UnreliableChannel) -> Self { 65 | UnreliableBincodeChannel { 66 | channel, 67 | pending_write: Vec::new(), 68 | } 69 | } 70 | 71 | pub fn into_inner(self) -> UnreliableChannel { 72 | self.channel 73 | } 74 | 75 | /// Maximum allowed message length based on the packet capacity of the provided `PacketPool`. 76 | /// 77 | /// Will never be greater than `MAX_PACKET_LEN - 2`. 78 | pub fn max_message_len(&self) -> u16 { 79 | self.channel.max_message_len() 80 | } 81 | 82 | /// Write the given serializable message type to the channel. 83 | /// 84 | /// Messages are coalesced into larger packets before being sent, so in order to guarantee that 85 | /// the message is actually sent, you must call `flush`. 86 | /// 87 | /// This method is cancel safe, it will never partially send a message, and completes 88 | /// immediately upon successfully queuing a message to send. 89 | pub async fn send(&mut self, msg: &M) -> Result<(), SendError> { 90 | future::poll_fn(|cx| self.poll_send_ready(cx)).await?; 91 | self.start_send(msg)?; 92 | Ok(()) 93 | } 94 | 95 | pub fn try_send(&mut self, msg: &M) -> Result { 96 | if self.try_send_ready()? { 97 | self.start_send(msg)?; 98 | Ok(true) 99 | } else { 100 | Ok(false) 101 | } 102 | } 103 | 104 | /// Finish sending any unsent coalesced packets. 105 | /// 106 | /// This *must* be called to guarantee that any sent messages are actually sent to the outgoing 107 | /// packet stream. 108 | /// 109 | /// This method is cancel safe. 110 | pub async fn flush(&mut self) -> Result<(), unreliable_channel::SendError> { 111 | future::poll_fn(|cx| self.poll_flush(cx)).await 112 | } 113 | 114 | pub fn try_flush(&mut self) -> Result { 115 | match self.poll_flush(&mut Context::from_waker(task::noop_waker_ref())) { 116 | Poll::Pending => Ok(false), 117 | Poll::Ready(Ok(())) => Ok(true), 118 | Poll::Ready(Err(err)) => Err(err), 119 | } 120 | } 121 | 122 | /// Receive a deserializable message type as soon as the next message is available. 123 | /// 124 | /// This method is cancel safe, it will never partially read a message or drop received 125 | /// messages. 126 | pub async fn recv<'a, M: Deserialize<'a>>(&'a mut self) -> Result { 127 | let bincode_config = self.bincode_config(); 128 | let msg = self.channel.recv().await?; 129 | Ok(bincode_config.deserialize(msg)?) 130 | } 131 | 132 | pub fn try_recv<'a, M: Deserialize<'a>>(&'a mut self) -> Result, RecvError> { 133 | match self.poll_recv::(&mut Context::from_waker(task::noop_waker_ref())) { 134 | Poll::Pending => Ok(None), 135 | Poll::Ready(Ok(val)) => Ok(Some(val)), 136 | Poll::Ready(Err(err)) => Err(err), 137 | } 138 | } 139 | 140 | pub fn poll_send_ready( 141 | &mut self, 142 | cx: &mut Context, 143 | ) -> Poll> { 144 | if !self.pending_write.is_empty() { 145 | ready!(self.channel.poll_send(cx, &self.pending_write))?; 146 | self.pending_write.clear(); 147 | } 148 | Poll::Ready(Ok(())) 149 | } 150 | 151 | pub fn try_send_ready(&mut self) -> Result { 152 | match self.poll_send_ready(&mut Context::from_waker(task::noop_waker_ref())) { 153 | Poll::Pending => Ok(false), 154 | Poll::Ready(Ok(())) => Ok(true), 155 | Poll::Ready(Err(err)) => Err(err), 156 | } 157 | } 158 | 159 | pub fn start_send(&mut self, msg: &M) -> Result<(), bincode::Error> { 160 | assert!(self.pending_write.is_empty()); 161 | 162 | let bincode_config = self.bincode_config(); 163 | bincode_config.serialize_into(&mut self.pending_write, msg)?; 164 | 165 | Ok(()) 166 | } 167 | 168 | pub fn poll_flush( 169 | &mut self, 170 | cx: &mut Context, 171 | ) -> Poll> { 172 | ready!(self.poll_send_ready(cx))?; 173 | ready!(self.channel.poll_flush(cx))?; 174 | Poll::Ready(Ok(())) 175 | } 176 | 177 | pub fn poll_recv<'a, M: Deserialize<'a>>( 178 | &'a mut self, 179 | cx: &mut Context, 180 | ) -> Poll> { 181 | let bincode_config = self.bincode_config(); 182 | let msg = ready!(self.channel.poll_recv(cx))?; 183 | Poll::Ready(Ok(bincode_config.deserialize::(msg)?)) 184 | } 185 | 186 | fn bincode_config(&self) -> impl bincode::Options + Copy { 187 | bincode::options().with_limit(self.max_message_len() as u64) 188 | } 189 | } 190 | 191 | /// Wrapper over an `UnreliableBincodeChannel` that only allows a single message type. 192 | pub struct UnreliableTypedChannel 193 | where 194 | T: Timer, 195 | P: PacketPool, 196 | { 197 | channel: UnreliableBincodeChannel, 198 | _phantom: PhantomData, 199 | } 200 | 201 | impl From> for UnreliableTypedChannel 202 | where 203 | T: Timer, 204 | P: PacketPool, 205 | { 206 | fn from(channel: UnreliableChannel) -> Self { 207 | Self::new(channel) 208 | } 209 | } 210 | 211 | impl UnreliableTypedChannel 212 | where 213 | T: Timer, 214 | P: PacketPool, 215 | { 216 | pub fn new(channel: UnreliableChannel) -> Self { 217 | Self { 218 | channel: UnreliableBincodeChannel::new(channel), 219 | _phantom: PhantomData, 220 | } 221 | } 222 | 223 | pub fn into_inner(self) -> UnreliableChannel { 224 | self.channel.into_inner() 225 | } 226 | 227 | pub async fn flush(&mut self) -> Result<(), unreliable_channel::SendError> { 228 | self.channel.flush().await 229 | } 230 | 231 | pub fn try_flush(&mut self) -> Result { 232 | self.channel.try_flush() 233 | } 234 | 235 | pub fn poll_flush( 236 | &mut self, 237 | cx: &mut Context, 238 | ) -> Poll> { 239 | self.channel.poll_flush(cx) 240 | } 241 | 242 | pub fn poll_send_ready( 243 | &mut self, 244 | cx: &mut Context, 245 | ) -> Poll> { 246 | self.channel.poll_send_ready(cx) 247 | } 248 | 249 | pub fn try_send_ready(&mut self) -> Result { 250 | self.channel.try_send_ready() 251 | } 252 | } 253 | 254 | impl UnreliableTypedChannel 255 | where 256 | T: Timer, 257 | P: PacketPool, 258 | M: Serialize, 259 | { 260 | pub async fn send(&mut self, msg: &M) -> Result<(), SendError> { 261 | self.channel.send(msg).await 262 | } 263 | 264 | pub fn try_send(&mut self, msg: &M) -> Result { 265 | self.channel.try_send(msg) 266 | } 267 | 268 | pub fn start_send(&mut self, msg: &M) -> Result<(), bincode::Error> { 269 | self.channel.start_send(msg) 270 | } 271 | } 272 | 273 | impl<'a, T, P, M> UnreliableTypedChannel 274 | where 275 | T: Timer, 276 | P: PacketPool, 277 | M: Deserialize<'a>, 278 | { 279 | pub async fn recv(&'a mut self) -> Result { 280 | self.channel.recv::().await 281 | } 282 | 283 | pub fn try_recv(&'a mut self) -> Result, RecvError> { 284 | self.channel.try_recv::() 285 | } 286 | 287 | pub fn poll_recv(&'a mut self, cx: &mut Context) -> Poll> { 288 | self.channel.poll_recv::(cx) 289 | } 290 | } 291 | -------------------------------------------------------------------------------- /src/unreliable_channel.rs: -------------------------------------------------------------------------------- 1 | use std::{ 2 | convert::TryInto, 3 | future::Future, 4 | mem, 5 | pin::Pin, 6 | task::{Context, Poll}, 7 | }; 8 | 9 | use byteorder::{ByteOrder, LittleEndian}; 10 | use futures::{future, ready, task, SinkExt, StreamExt}; 11 | use thiserror::Error; 12 | 13 | use crate::{ 14 | bandwidth_limiter::BandwidthLimiter, 15 | packet::{Packet, PacketPool, MAX_PACKET_LEN}, 16 | runtime::Timer, 17 | spsc, 18 | }; 19 | 20 | #[derive(Debug, Error)] 21 | /// Fatal error due to channel disconnection. 22 | #[error("incoming or outgoing packet channel has been disconnected")] 23 | pub struct Disconnected; 24 | 25 | #[derive(Debug, Error)] 26 | pub enum SendError { 27 | #[error(transparent)] 28 | Disconnected(#[from] Disconnected), 29 | /// Non-fatal error, message is unsent. 30 | #[error("message is larger than fits in the maximum packet size")] 31 | TooBig, 32 | } 33 | 34 | #[derive(Debug, Error)] 35 | pub enum RecvError { 36 | #[error(transparent)] 37 | Disconnected(#[from] Disconnected), 38 | /// Non-fatal error, the remainder of the incoming packet is dropped. 39 | #[error("incoming packet has bad message format")] 40 | BadFormat, 41 | } 42 | 43 | #[derive(Debug, Clone, PartialEq)] 44 | pub struct Settings { 45 | /// The target outgoing bandwidth, in bytes / sec. 46 | pub bandwidth: u32, 47 | /// The maximum amount of bandwidth credit that can accumulate. This is the maximum bytes that 48 | /// will be sent in a single burst. 49 | pub burst_bandwidth: u32, 50 | } 51 | 52 | /// Turns a stream of unreliable, unordered packets into a stream of unreliable, unordered messages. 53 | pub struct UnreliableChannel 54 | where 55 | T: Timer, 56 | P: PacketPool, 57 | { 58 | timer: T, 59 | packet_pool: P, 60 | bandwidth_limiter: BandwidthLimiter, 61 | sender: spsc::Sender, 62 | receiver: spsc::Receiver, 63 | out_packet: P::Packet, 64 | in_packet: Option<(P::Packet, usize)>, 65 | delay_until_available: Pin>>, 66 | } 67 | 68 | impl UnreliableChannel 69 | where 70 | T: Timer, 71 | P: PacketPool, 72 | { 73 | pub fn new( 74 | timer: T, 75 | mut packet_pool: P, 76 | settings: Settings, 77 | sender: spsc::Sender, 78 | receiver: spsc::Receiver, 79 | ) -> Self { 80 | let out_packet = packet_pool.acquire(); 81 | let bandwidth_limiter = 82 | BandwidthLimiter::new(&timer, settings.bandwidth, settings.burst_bandwidth); 83 | UnreliableChannel { 84 | timer, 85 | packet_pool, 86 | bandwidth_limiter, 87 | receiver, 88 | sender, 89 | out_packet, 90 | in_packet: None, 91 | delay_until_available: Box::pin(None), 92 | } 93 | } 94 | 95 | /// Maximum allowed message length based on the packet capacity of the provided `PacketPool`. 96 | /// 97 | /// Will never be greater than `MAX_PACKET_LEN - 2`. 98 | pub fn max_message_len(&self) -> u16 { 99 | self.packet_pool.capacity().min(MAX_PACKET_LEN as usize) as u16 - 2 100 | } 101 | 102 | /// Write the given message to the channel. 103 | /// 104 | /// Messages are coalesced into larger packets before being sent, so in order to guarantee that 105 | /// the message is actually sent, you must call `flush`. 106 | /// 107 | /// Messages have a maximum size based on the size of the packets returned from the packet pool. 108 | /// Two bytes are used to encode the length of the message, so the maximum message length is 109 | /// `packet.len() - 2`, for whatever packet sizes are returned by the pool. 110 | /// 111 | /// This method is cancel safe, it will never partially send a message, and the future will 112 | /// complete immediately after writing a message. 113 | pub async fn send(&mut self, msg: &[u8]) -> Result<(), SendError> { 114 | future::poll_fn(|cx| self.poll_send(cx, msg)).await 115 | } 116 | 117 | pub fn try_send(&mut self, msg: &[u8]) -> Result { 118 | match self.poll_send(&mut Context::from_waker(task::noop_waker_ref()), msg) { 119 | Poll::Pending => Ok(false), 120 | Poll::Ready(Ok(())) => Ok(true), 121 | Poll::Ready(Err(err)) => Err(err), 122 | } 123 | } 124 | 125 | /// Finish sending any unsent coalesced packets. 126 | /// 127 | /// This *must* be called to guarantee that any sent messages are actually sent to the outgoing 128 | /// packet stream. 129 | /// 130 | /// This method is cancel safe. 131 | pub async fn flush(&mut self) -> Result<(), Disconnected> { 132 | future::poll_fn(|cx| self.poll_flush(cx)).await 133 | } 134 | 135 | pub fn try_flush(&mut self) -> Result { 136 | match self.poll_flush(&mut Context::from_waker(task::noop_waker_ref())) { 137 | Poll::Pending => Ok(false), 138 | Poll::Ready(Ok(())) => Ok(true), 139 | Poll::Ready(Err(err)) => Err(err), 140 | } 141 | } 142 | 143 | /// Receive a message into the provide buffer. 144 | /// 145 | /// If the received message fits into the provided buffer, this will return `Ok(message_len)`, 146 | /// otherwise it will return `Err(RecvError::TooBig)`. 147 | /// 148 | /// This method is cancel safe, it will never partially read a message or drop received 149 | /// messages. 150 | pub async fn recv(&mut self) -> Result<&[u8], RecvError> { 151 | future::poll_fn(|cx| self.poll_recv_ready(cx)).await?; 152 | self.recv_next() 153 | } 154 | 155 | pub fn try_recv(&mut self) -> Result, RecvError> { 156 | match self.poll_recv_ready(&mut Context::from_waker(task::noop_waker_ref())) { 157 | Poll::Pending => Ok(None), 158 | Poll::Ready(Ok(())) => Ok(Some(self.recv_next()?)), 159 | Poll::Ready(Err(err)) => Err(err), 160 | } 161 | } 162 | 163 | pub fn poll_send(&mut self, cx: &mut Context, msg: &[u8]) -> Poll> { 164 | ready!(self.poll_send_ready(cx, msg.len()))?; 165 | let mut send = self.start_send(); 166 | send.buffer()[0..msg.len()].copy_from_slice(msg); 167 | send.finish(msg.len()); 168 | Poll::Ready(Ok(())) 169 | } 170 | 171 | /// Wait until we can send at least a `msg_len` length message via `start_send`. 172 | /// 173 | /// The available message length may be more than requested, if `msg_len` is zero, then this 174 | /// will return as soon as a message of any length can be sent. 175 | pub fn poll_send_ready( 176 | &mut self, 177 | cx: &mut Context, 178 | msg_len: usize, 179 | ) -> Poll> { 180 | let msg_len: u16 = msg_len.try_into().map_err(|_| SendError::TooBig)?; 181 | 182 | let start = self.out_packet.len(); 183 | if self.packet_pool.capacity() - start < msg_len as usize + 2 { 184 | ready!(self.poll_flush(cx))?; 185 | 186 | if self.packet_pool.capacity() < msg_len as usize + 2 { 187 | return Poll::Ready(Err(SendError::TooBig)); 188 | } 189 | } 190 | 191 | Poll::Ready(Ok(())) 192 | } 193 | 194 | /// Start sending a message up to the maximum remaining available message length. 195 | /// 196 | /// # Panics 197 | /// May panic if called without `poll_send_ready` being returned for some message length. 198 | pub fn start_send(&mut self) -> StartSend { 199 | StartSend::new(&mut self.out_packet, self.packet_pool.capacity()) 200 | } 201 | 202 | pub fn poll_flush(&mut self, cx: &mut Context) -> Poll> { 203 | if self.out_packet.is_empty() { 204 | return Poll::Ready(Ok(())); 205 | } 206 | 207 | if self.delay_until_available.is_none() { 208 | self.bandwidth_limiter.update_available(&self.timer); 209 | if let Some(delay) = self.bandwidth_limiter.delay_until_available(&self.timer) { 210 | self.delay_until_available.set(Some(delay)); 211 | } 212 | } 213 | 214 | if let Some(delay) = self.delay_until_available.as_mut().as_pin_mut() { 215 | ready!(delay.poll(cx)); 216 | self.delay_until_available.set(None); 217 | } 218 | 219 | ready!(self.sender.poll_ready_unpin(cx)).map_err(|_| Disconnected)?; 220 | 221 | let out_packet = mem::replace(&mut self.out_packet, self.packet_pool.acquire()); 222 | self.bandwidth_limiter.take_bytes(out_packet.len() as u32); 223 | self.sender 224 | .start_send_unpin(out_packet) 225 | .map_err(|_| Disconnected)?; 226 | 227 | self.sender.poll_flush_unpin(cx).map_err(|_| Disconnected) 228 | } 229 | 230 | pub fn poll_recv(&mut self, cx: &mut Context) -> Poll> { 231 | ready!(self.poll_recv_ready(cx))?; 232 | Poll::Ready(self.recv_next()) 233 | } 234 | 235 | fn poll_recv_ready(&mut self, cx: &mut Context) -> Poll> { 236 | if let Some((packet, in_pos)) = &self.in_packet { 237 | if *in_pos == packet.len() { 238 | self.in_packet = None; 239 | } 240 | } 241 | 242 | if self.in_packet.is_none() { 243 | let packet = ready!(self.receiver.poll_next_unpin(cx)).ok_or(Disconnected)?; 244 | self.in_packet = Some((packet, 0)); 245 | } 246 | 247 | Poll::Ready(Ok(())) 248 | } 249 | 250 | fn recv_next(&mut self) -> Result<&[u8], RecvError> { 251 | let (packet, in_pos) = self.in_packet.as_mut().unwrap(); 252 | assert_ne!(*in_pos, packet.len()); 253 | 254 | if *in_pos + 2 > packet.len() { 255 | *in_pos = packet.len(); 256 | return Err(RecvError::BadFormat); 257 | } 258 | let length = LittleEndian::read_u16(&packet[*in_pos..*in_pos + 2]) as usize; 259 | *in_pos += 2; 260 | 261 | if *in_pos + length > packet.len() { 262 | *in_pos = packet.len(); 263 | return Err(RecvError::BadFormat); 264 | } 265 | 266 | let msg = &packet[*in_pos..*in_pos + length]; 267 | *in_pos += length; 268 | 269 | Ok(msg) 270 | } 271 | } 272 | 273 | pub struct StartSend<'a, P> { 274 | packet: &'a mut P, 275 | start: usize, 276 | capacity: usize, 277 | } 278 | 279 | impl<'a, P: Packet> StartSend<'a, P> { 280 | fn new(packet: &'a mut P, capacity: usize) -> Self { 281 | assert!( 282 | capacity >= packet.len() + 2, 283 | "not enough room to write size header" 284 | ); 285 | let start = packet.len(); 286 | packet.resize(capacity, 0); 287 | Self { 288 | packet, 289 | start, 290 | capacity, 291 | } 292 | } 293 | 294 | /// Returns the buffer to write the outgoing message into. 295 | pub fn buffer(&mut self) -> &mut [u8] { 296 | &mut self.packet[self.start + 2..] 297 | } 298 | 299 | /// Finish writing a message that has been written into the provided buffer. 300 | /// 301 | /// # Panics 302 | /// Panics if called with a message length larger than the size of the provided buffer. 303 | pub fn finish(self, msg_len: usize) { 304 | assert!( 305 | msg_len < self.capacity - self.start - 2, 306 | "cannot send packet greater than size of provided buffer" 307 | ); 308 | let msg_len: u16 = msg_len.try_into().unwrap(); 309 | LittleEndian::write_u16(&mut self.packet[self.start..self.start + 2], msg_len); 310 | self.packet.truncate(self.start + msg_len as usize + 2); 311 | } 312 | } 313 | -------------------------------------------------------------------------------- /tests/compressed_bincode_channel.rs: -------------------------------------------------------------------------------- 1 | use std::time::Duration; 2 | 3 | use futures::channel::oneshot; 4 | use rand::{rngs::SmallRng, thread_rng, RngCore, SeedableRng}; 5 | 6 | use turbulence::{ 7 | buffer::BufferPacketPool, 8 | compressed_bincode_channel::CompressedBincodeChannel, 9 | reliable_channel::{ReliableChannel, Settings}, 10 | runtime::Spawn, 11 | spsc, 12 | }; 13 | 14 | mod util; 15 | 16 | use self::util::{condition_link, LinkCondition, SimpleBufferPool, SimpleRuntime}; 17 | 18 | #[test] 19 | fn test_compressed_bincode_channel() { 20 | const SETTINGS: Settings = Settings { 21 | bandwidth: 2048, 22 | recv_window_size: 512, 23 | send_window_size: 512, 24 | burst_bandwidth: 512, 25 | init_send: 256, 26 | resend_time: Duration::from_millis(50), 27 | initial_rtt: Duration::from_millis(100), 28 | max_rtt: Duration::from_millis(2000), 29 | rtt_update_factor: 0.1, 30 | rtt_resend_factor: 1.5, 31 | }; 32 | 33 | const CONDITION: LinkCondition = LinkCondition { 34 | loss: 0.2, 35 | duplicate: 0.05, 36 | delay: Duration::from_millis(40), 37 | jitter: Duration::from_millis(10), 38 | }; 39 | 40 | let packet_pool = BufferPacketPool::new(SimpleBufferPool(1000)); 41 | let mut runtime = SimpleRuntime::new(); 42 | 43 | let (asend, acondrecv) = spsc::channel(2); 44 | let (acondsend, arecv) = spsc::channel(2); 45 | condition_link( 46 | CONDITION, 47 | runtime.handle(), 48 | runtime.handle(), 49 | packet_pool.clone(), 50 | SmallRng::from_rng(thread_rng()).unwrap(), 51 | acondsend, 52 | acondrecv, 53 | ); 54 | 55 | let (bsend, bcondrecv) = spsc::channel(2); 56 | let (bcondsend, brecv) = spsc::channel(2); 57 | condition_link( 58 | CONDITION, 59 | runtime.handle(), 60 | runtime.handle(), 61 | packet_pool.clone(), 62 | SmallRng::from_rng(thread_rng()).unwrap(), 63 | bcondsend, 64 | bcondrecv, 65 | ); 66 | 67 | let mut stream1 = CompressedBincodeChannel::new(ReliableChannel::new( 68 | runtime.handle(), 69 | runtime.handle(), 70 | packet_pool.clone(), 71 | SETTINGS.clone(), 72 | bsend, 73 | arecv, 74 | )); 75 | let mut stream2 = CompressedBincodeChannel::new(ReliableChannel::new( 76 | runtime.handle(), 77 | runtime.handle(), 78 | packet_pool.clone(), 79 | SETTINGS.clone(), 80 | asend, 81 | brecv, 82 | )); 83 | 84 | let (a_done_send, mut a_done) = oneshot::channel(); 85 | runtime.spawn({ 86 | async move { 87 | for i in 0..100 { 88 | let send_val = vec![i as u8 + 13; i + 25]; 89 | stream1.send(&send_val).await.unwrap(); 90 | } 91 | stream1.flush().await.unwrap(); 92 | 93 | for i in 0..100 { 94 | let recv_val = stream1.recv::>().await.unwrap(); 95 | assert_eq!(recv_val.len(), i + 17); 96 | } 97 | 98 | let _ = a_done_send.send(stream1); 99 | } 100 | }); 101 | 102 | let (b_done_send, mut b_done) = oneshot::channel(); 103 | runtime.spawn({ 104 | async move { 105 | for i in 0..100 { 106 | let recv_val = stream2.recv::>().await.unwrap(); 107 | assert_eq!(recv_val, vec![i as u8 + 13; i + 25].as_slice()); 108 | } 109 | 110 | for i in 0..100 { 111 | let mut send_val = vec![0; i + 17]; 112 | rand::thread_rng().fill_bytes(&mut send_val); 113 | stream2.send(&send_val).await.unwrap(); 114 | } 115 | stream2.flush().await.unwrap(); 116 | 117 | let _ = b_done_send.send(stream2); 118 | } 119 | }); 120 | 121 | let mut a_done_stream = None; 122 | let mut b_done_stream = None; 123 | for _ in 0..100_000 { 124 | a_done_stream = a_done_stream.or_else(|| a_done.try_recv().unwrap()); 125 | b_done_stream = b_done_stream.or_else(|| b_done.try_recv().unwrap()); 126 | 127 | if a_done_stream.is_some() && b_done_stream.is_some() { 128 | return; 129 | } 130 | 131 | runtime.run_until_stalled(); 132 | runtime.advance_time(50); 133 | } 134 | 135 | panic!("didn't finish in time"); 136 | } 137 | -------------------------------------------------------------------------------- /tests/message_channels.rs: -------------------------------------------------------------------------------- 1 | use std::time::Duration; 2 | 3 | use futures::{ 4 | channel::oneshot, 5 | future::{self, Either}, 6 | SinkExt, StreamExt, 7 | }; 8 | use serde::{Deserialize, Serialize}; 9 | 10 | use turbulence::{ 11 | buffer::BufferPacketPool, 12 | message_channels::{MessageChannelMode, MessageChannelSettings, MessageChannelsBuilder}, 13 | packet_multiplexer::PacketMultiplexer, 14 | reliable_channel, 15 | runtime::Spawn, 16 | unreliable_channel, 17 | }; 18 | 19 | mod util; 20 | 21 | use self::util::{SimpleBufferPool, SimpleRuntime}; 22 | 23 | // Define two message types, `Message1` and `Message2` 24 | 25 | // `Message1` is a reliable message on channel "0" that has a maximum bandwidth of 4KB/s 26 | 27 | #[derive(Serialize, Deserialize)] 28 | struct Message1(i32); 29 | 30 | const MESSAGE1_SETTINGS: MessageChannelSettings = MessageChannelSettings { 31 | channel: 0, 32 | channel_mode: MessageChannelMode::Reliable(reliable_channel::Settings { 33 | bandwidth: 4096, 34 | burst_bandwidth: 1024, 35 | recv_window_size: 1024, 36 | send_window_size: 1024, 37 | init_send: 512, 38 | resend_time: Duration::from_millis(100), 39 | initial_rtt: Duration::from_millis(200), 40 | max_rtt: Duration::from_secs(2), 41 | rtt_update_factor: 0.1, 42 | rtt_resend_factor: 1.5, 43 | }), 44 | message_buffer_size: 8, 45 | packet_buffer_size: 8, 46 | }; 47 | 48 | // `Message2` is an unreliable message type on channel "1" 49 | 50 | #[derive(Serialize, Deserialize)] 51 | struct Message2(i32); 52 | 53 | const MESSAGE2_SETTINGS: MessageChannelSettings = MessageChannelSettings { 54 | channel: 1, 55 | channel_mode: MessageChannelMode::Unreliable(unreliable_channel::Settings { 56 | bandwidth: 4096, 57 | burst_bandwidth: 1024, 58 | }), 59 | message_buffer_size: 8, 60 | packet_buffer_size: 8, 61 | }; 62 | 63 | #[test] 64 | fn test_message_channels() { 65 | let mut runtime = SimpleRuntime::new(); 66 | let pool = BufferPacketPool::new(SimpleBufferPool(32)); 67 | 68 | // Set up two packet multiplexers, one for our sending "A" side and one for our receiving "B" 69 | // side. They should both have exactly the same message types registered. 70 | 71 | let mut multiplexer_a = PacketMultiplexer::new(); 72 | let mut builder_a = MessageChannelsBuilder::new(runtime.handle(), runtime.handle(), pool); 73 | builder_a.register::(MESSAGE1_SETTINGS).unwrap(); 74 | builder_a.register::(MESSAGE2_SETTINGS).unwrap(); 75 | let mut channels_a = builder_a.build(&mut multiplexer_a); 76 | 77 | let mut multiplexer_b = PacketMultiplexer::new(); 78 | let mut builder_b = MessageChannelsBuilder::new(runtime.handle(), runtime.handle(), pool); 79 | builder_b.register::(MESSAGE1_SETTINGS).unwrap(); 80 | builder_b.register::(MESSAGE2_SETTINGS).unwrap(); 81 | let mut channels_b = builder_b.build(&mut multiplexer_b); 82 | 83 | // Spawn a task that simulates a perfect network connection, and takes outgoing packets from 84 | // each multiplexer and gives it to the other. 85 | runtime.spawn(async move { 86 | // We need to send packets bidirectionally from A -> B and B -> A, because reliable message 87 | // channels must have a way to send acknowledgments. 88 | let (mut a_incoming, mut a_outgoing) = multiplexer_a.start(); 89 | let (mut b_incoming, mut b_outgoing) = multiplexer_b.start(); 90 | loop { 91 | // How to best send packets from the multiplexer to the internet and vice versa is 92 | // somewhat complex. This is not a great example of how to do it. 93 | // 94 | // Calling `x_incoming.send(packet).await` here is using `IncomingMultiplexedPackets` 95 | // `Sink` implementation, which forwards to the incoming spsc channel for whatever 96 | // channel this packet is for. `turbulence` *only* uses sync channels with static 97 | // size, so it is expected that this buffer might be full. You might want to instead 98 | // use `IncomingMultiplexedPackets::try_send` here and if the incoming buffer is full, 99 | // simply drop the packet. A full buffer means some level of the pipeline cannot keep 100 | // up, and dropping the packet rather than blocking on delivering here means that 101 | // a backup on one channel will not potentially block other channels from receiving 102 | // packets. 103 | // 104 | // On the outgoing side, since `turbulence` assumes an unreliable transport, it also 105 | // assumes that the actual outgoing transport can send at more or less an arbitrary 106 | // rate. For this reason, the different internal channel types *block* on sending 107 | // outgoing packets. It is assumed that the outgoing packet buffer would only be full 108 | // under very high, temporary CPU load on the host, and they block to let the task that 109 | // actually sends packets catch up. This assumption works if the outgoing stream is only 110 | // really CPU bound: that it is not harmful to block on outgoing packets because we're 111 | // cooperating with a task that will send UDP packets as fast as it can anyway, so we 112 | // won't be blocking for long (and it's better not to burn up even more CPU making more 113 | // packets that might not be sent). 114 | // 115 | // So why the difference, why drop incoming packets but block on outgoing packets? Well, 116 | // this again assumes that the task that sends packets is utterly simple, that it is a 117 | // task that just calls `sendto` or equivalent as fast as it can. On the incoming side 118 | // the pipeline is much longer, and will usually include the actual main game loop. 119 | // "Blocking" in this case may simply mean only processing a maximum number of incoming 120 | // messages per tick, or something along those lines. In that case, since "blocking" is 121 | // not a function of purely CPU load, dropping incoming packets for fairness and latency 122 | // may be reasonable. On the outgoing side, we're not assuming that we may have somehow 123 | // accidentally *sent* too much data, we of course assume that we are following our 124 | // *own* rules, so the only cause of a backup should be very high CPU load. 125 | // 126 | // Since this test unrealistically assumes perfect delivery of an unreliable channel, 127 | // and since this is all hard to simulate in an example with no actual network involved, 128 | // we just provide perfect instant delivery. None of the subtlety of doing this in a 129 | // real project is captured in this simplistic example. 130 | match future::select(a_outgoing.next(), b_outgoing.next()).await { 131 | Either::Left((Some(packet), _)) => { 132 | b_incoming.send(packet).await.unwrap(); 133 | } 134 | Either::Right((Some(packet), _)) => { 135 | a_incoming.send(packet).await.unwrap(); 136 | } 137 | Either::Left((None, _)) | Either::Right((None, _)) => break, 138 | } 139 | } 140 | }); 141 | 142 | let (is_done_send, mut is_done_recv) = oneshot::channel(); 143 | runtime.spawn(async move { 144 | // Now send some traffic across... 145 | 146 | // We're using the async `MessageChannels` API, but in a game you might use the sync API. 147 | channels_a.async_send(Message1(42)).await.unwrap(); 148 | channels_a.flush::(); 149 | assert_eq!(channels_b.async_recv::().await.unwrap().0, 42); 150 | 151 | // Since our underlying simulated network is perfect, our unreliable message will always 152 | // arrive. 153 | channels_a.async_send(Message2(13)).await.unwrap(); 154 | channels_a.flush::(); 155 | assert_eq!(channels_b.async_recv::().await.unwrap().0, 13); 156 | 157 | // Each message channel is independent of the others, and they all have their own 158 | // independent instances of message coalescing and reliability protocols. 159 | 160 | channels_a.async_send(Message1(20)).await.unwrap(); 161 | channels_a.async_send(Message2(30)).await.unwrap(); 162 | channels_a.async_send(Message1(21)).await.unwrap(); 163 | channels_a.async_send(Message2(31)).await.unwrap(); 164 | channels_a.async_send(Message1(22)).await.unwrap(); 165 | channels_a.async_send(Message2(32)).await.unwrap(); 166 | channels_a.flush::(); 167 | channels_a.flush::(); 168 | 169 | assert_eq!(channels_b.async_recv::().await.unwrap().0, 20); 170 | assert_eq!(channels_b.async_recv::().await.unwrap().0, 21); 171 | assert_eq!(channels_b.async_recv::().await.unwrap().0, 22); 172 | 173 | assert_eq!(channels_b.async_recv::().await.unwrap().0, 30); 174 | assert_eq!(channels_b.async_recv::().await.unwrap().0, 31); 175 | assert_eq!(channels_b.async_recv::().await.unwrap().0, 32); 176 | 177 | is_done_send.send(()).unwrap(); 178 | }); 179 | 180 | for _ in 0..100_000 { 181 | if is_done_recv.try_recv().unwrap().is_some() { 182 | return; 183 | } 184 | 185 | runtime.run_until_stalled(); 186 | runtime.advance_time(50); 187 | } 188 | 189 | panic!("didn't finish in time"); 190 | } 191 | -------------------------------------------------------------------------------- /tests/packet_multiplexer.rs: -------------------------------------------------------------------------------- 1 | use futures::{ 2 | executor::LocalPool, 3 | future::{self, Either}, 4 | task::SpawnExt, 5 | SinkExt, StreamExt, 6 | }; 7 | 8 | use turbulence::{ 9 | buffer::BufferPacketPool, 10 | packet::{Packet, PacketPool}, 11 | packet_multiplexer::{MuxPacketPool, PacketMultiplexer}, 12 | }; 13 | 14 | mod util; 15 | 16 | use self::util::SimpleBufferPool; 17 | 18 | #[test] 19 | fn test_multiplexer() { 20 | let mut pool = LocalPool::new(); 21 | let spawner = pool.spawner(); 22 | let mut packet_pool = MuxPacketPool::new(BufferPacketPool::new(SimpleBufferPool(32))); 23 | 24 | let mut multiplexer_a = PacketMultiplexer::new(); 25 | let (mut sender4a, mut receiver4a, _) = multiplexer_a.open_channel(4, 8).unwrap(); 26 | let (mut sender32a, mut receiver32a, _) = multiplexer_a.open_channel(32, 8).unwrap(); 27 | 28 | let mut multiplexer_b = PacketMultiplexer::new(); 29 | let (mut sender4b, mut receiver4b, _) = multiplexer_b.open_channel(4, 8).unwrap(); 30 | let (mut sender32b, mut receiver32b, _) = multiplexer_b.open_channel(32, 8).unwrap(); 31 | 32 | spawner 33 | .spawn(async move { 34 | let (mut a_incoming, mut a_outgoing) = multiplexer_a.start(); 35 | let (mut b_incoming, mut b_outgoing) = multiplexer_b.start(); 36 | loop { 37 | match future::select(a_outgoing.next(), b_outgoing.next()).await { 38 | Either::Left((Some(packet), _)) => { 39 | b_incoming.send(packet).await.unwrap(); 40 | } 41 | Either::Right((Some(packet), _)) => { 42 | a_incoming.send(packet).await.unwrap(); 43 | } 44 | Either::Left((None, _)) | Either::Right((None, _)) => break, 45 | } 46 | } 47 | }) 48 | .unwrap(); 49 | 50 | spawner 51 | .spawn(async move { 52 | let mut packet = packet_pool.acquire(); 53 | packet.resize(1, 17); 54 | sender4a.send(packet).await.unwrap(); 55 | 56 | let mut packet = packet_pool.acquire(); 57 | packet.resize(1, 18); 58 | sender4b.send(packet).await.unwrap(); 59 | 60 | let mut packet = packet_pool.acquire(); 61 | packet.resize(1, 19); 62 | sender32a.send(packet).await.unwrap(); 63 | 64 | let mut packet = packet_pool.acquire(); 65 | packet.resize(1, 20); 66 | sender32b.send(packet).await.unwrap(); 67 | 68 | let packet = receiver4a.next().await.unwrap(); 69 | assert_eq!(packet[0], 18); 70 | 71 | let packet = receiver4b.next().await.unwrap(); 72 | assert_eq!(packet[0], 17); 73 | 74 | let packet = receiver32a.next().await.unwrap(); 75 | assert_eq!(packet[0], 20); 76 | 77 | let packet = receiver32b.next().await.unwrap(); 78 | assert_eq!(packet[0], 19); 79 | }) 80 | .unwrap(); 81 | 82 | pool.run(); 83 | } 84 | -------------------------------------------------------------------------------- /tests/reliable_bincode_channel.rs: -------------------------------------------------------------------------------- 1 | use std::time::Duration; 2 | 3 | use futures::channel::oneshot; 4 | use rand::{rngs::SmallRng, thread_rng, SeedableRng}; 5 | 6 | use turbulence::{ 7 | buffer::BufferPacketPool, 8 | reliable_bincode_channel::ReliableBincodeChannel, 9 | reliable_channel::{ReliableChannel, Settings}, 10 | runtime::Spawn, 11 | spsc, 12 | }; 13 | 14 | mod util; 15 | 16 | use self::util::{condition_link, LinkCondition, SimpleBufferPool, SimpleRuntime}; 17 | 18 | #[test] 19 | fn test_reliable_bincode_channel() { 20 | const SETTINGS: Settings = Settings { 21 | bandwidth: 2048, 22 | burst_bandwidth: 512, 23 | recv_window_size: 512, 24 | send_window_size: 512, 25 | init_send: 256, 26 | resend_time: Duration::from_millis(50), 27 | initial_rtt: Duration::from_millis(100), 28 | max_rtt: Duration::from_millis(2000), 29 | rtt_update_factor: 0.1, 30 | rtt_resend_factor: 1.5, 31 | }; 32 | 33 | const CONDITION: LinkCondition = LinkCondition { 34 | loss: 0.2, 35 | duplicate: 0.05, 36 | delay: Duration::from_millis(40), 37 | jitter: Duration::from_millis(10), 38 | }; 39 | 40 | let packet_pool = BufferPacketPool::new(SimpleBufferPool(1000)); 41 | let mut runtime = SimpleRuntime::new(); 42 | 43 | let (asend, acondrecv) = spsc::channel(2); 44 | let (acondsend, arecv) = spsc::channel(2); 45 | condition_link( 46 | CONDITION, 47 | runtime.handle(), 48 | runtime.handle(), 49 | packet_pool.clone(), 50 | SmallRng::from_rng(thread_rng()).unwrap(), 51 | acondsend, 52 | acondrecv, 53 | ); 54 | 55 | let (bsend, bcondrecv) = spsc::channel(2); 56 | let (bcondsend, brecv) = spsc::channel(2); 57 | condition_link( 58 | CONDITION, 59 | runtime.handle(), 60 | runtime.handle(), 61 | packet_pool.clone(), 62 | SmallRng::from_rng(thread_rng()).unwrap(), 63 | bcondsend, 64 | bcondrecv, 65 | ); 66 | 67 | let mut stream1 = ReliableBincodeChannel::new(ReliableChannel::new( 68 | runtime.handle(), 69 | runtime.handle(), 70 | packet_pool.clone(), 71 | SETTINGS.clone(), 72 | bsend, 73 | arecv, 74 | )); 75 | let mut stream2 = ReliableBincodeChannel::new(ReliableChannel::new( 76 | runtime.handle(), 77 | runtime.handle(), 78 | packet_pool.clone(), 79 | SETTINGS.clone(), 80 | asend, 81 | brecv, 82 | )); 83 | 84 | let (a_done_send, mut a_done) = oneshot::channel(); 85 | runtime.spawn({ 86 | async move { 87 | for i in 0..100 { 88 | let send_val = vec![i as u8 + 42; i + 25]; 89 | stream1.send(&send_val).await.unwrap(); 90 | } 91 | stream1.flush().await.unwrap(); 92 | 93 | for i in 0..100 { 94 | let recv_val = stream1.recv::<&[u8]>().await.unwrap(); 95 | assert_eq!(recv_val, vec![i as u8 + 64; i + 50].as_slice()); 96 | } 97 | 98 | let _ = a_done_send.send(stream1); 99 | } 100 | }); 101 | 102 | let (b_done_send, mut b_done) = oneshot::channel(); 103 | runtime.spawn({ 104 | async move { 105 | for i in 0..100 { 106 | let recv_val = stream2.recv::<&[u8]>().await.unwrap(); 107 | assert_eq!(recv_val, vec![i as u8 + 42; i + 25].as_slice()); 108 | } 109 | 110 | for i in 0..100 { 111 | let send_val = vec![i as u8 + 64; i + 50]; 112 | stream2.send(&send_val).await.unwrap(); 113 | } 114 | stream2.flush().await.unwrap(); 115 | 116 | let _ = b_done_send.send(stream2); 117 | } 118 | }); 119 | 120 | let mut a_done_stream = None; 121 | let mut b_done_stream = None; 122 | for _ in 0..100_000 { 123 | a_done_stream = a_done_stream.or_else(|| a_done.try_recv().unwrap()); 124 | b_done_stream = b_done_stream.or_else(|| b_done.try_recv().unwrap()); 125 | 126 | if a_done_stream.is_some() && b_done_stream.is_some() { 127 | return; 128 | } 129 | 130 | runtime.run_until_stalled(); 131 | runtime.advance_time(50); 132 | } 133 | 134 | panic!("didn't finish in time"); 135 | } 136 | -------------------------------------------------------------------------------- /tests/reliable_channel.rs: -------------------------------------------------------------------------------- 1 | use std::time::Duration; 2 | 3 | use futures::channel::oneshot; 4 | use rand::{rngs::SmallRng, thread_rng, SeedableRng}; 5 | 6 | use turbulence::{ 7 | buffer::BufferPacketPool, 8 | reliable_channel::{ReliableChannel, Settings}, 9 | runtime::{Spawn, Timer}, 10 | spsc, 11 | }; 12 | 13 | mod util; 14 | 15 | use self::util::{condition_link, LinkCondition, SimpleBufferPool, SimpleRuntime}; 16 | 17 | #[test] 18 | fn test_reliable_stream() { 19 | const SETTINGS: Settings = Settings { 20 | bandwidth: 32768, 21 | burst_bandwidth: 4096, 22 | recv_window_size: 16384, 23 | send_window_size: 16384, 24 | init_send: 512, 25 | resend_time: Duration::from_millis(50), 26 | initial_rtt: Duration::from_millis(100), 27 | max_rtt: Duration::from_millis(2000), 28 | rtt_update_factor: 0.1, 29 | rtt_resend_factor: 1.5, 30 | }; 31 | 32 | const CONDITION: LinkCondition = LinkCondition { 33 | loss: 0.4, 34 | duplicate: 0.1, 35 | delay: Duration::from_millis(30), 36 | jitter: Duration::from_millis(20), 37 | }; 38 | 39 | let packet_pool = BufferPacketPool::new(SimpleBufferPool(1000)); 40 | let mut runtime = SimpleRuntime::new(); 41 | 42 | let (asend, acondrecv) = spsc::channel(2); 43 | let (acondsend, arecv) = spsc::channel(2); 44 | condition_link( 45 | CONDITION, 46 | runtime.handle(), 47 | runtime.handle(), 48 | packet_pool.clone(), 49 | SmallRng::from_rng(thread_rng()).unwrap(), 50 | acondsend, 51 | acondrecv, 52 | ); 53 | 54 | let (bsend, bcondrecv) = spsc::channel(2); 55 | let (bcondsend, brecv) = spsc::channel(2); 56 | condition_link( 57 | CONDITION, 58 | runtime.handle(), 59 | runtime.handle(), 60 | packet_pool.clone(), 61 | SmallRng::from_rng(thread_rng()).unwrap(), 62 | bcondsend, 63 | bcondrecv, 64 | ); 65 | 66 | let mut stream1 = ReliableChannel::new( 67 | runtime.handle(), 68 | runtime.handle(), 69 | packet_pool.clone(), 70 | SETTINGS, 71 | bsend, 72 | arecv, 73 | ); 74 | let mut stream2 = ReliableChannel::new( 75 | runtime.handle(), 76 | runtime.handle(), 77 | packet_pool.clone(), 78 | SETTINGS, 79 | asend, 80 | brecv, 81 | ); 82 | 83 | const END_POS: usize = 86_753; 84 | const FLUSH_EVERY: usize = 2000; 85 | const SEND_DELAY_NEAR: usize = 30_000; 86 | const RECV_DELAY_NEAR: usize = 70_000; 87 | 88 | let (a_done_send, mut a_done) = oneshot::channel(); 89 | runtime.spawn({ 90 | let runtime_handle = runtime.handle(); 91 | async move { 92 | let mut send_buffer = [0; 512]; 93 | let mut c = 0; 94 | 95 | loop { 96 | for i in 0..send_buffer.len() { 97 | send_buffer[i] = (c + i) as u8; 98 | } 99 | let len = stream1 100 | .write(&send_buffer[0..send_buffer.len().min(END_POS - c)]) 101 | .await 102 | .unwrap(); 103 | 104 | if c % FLUSH_EVERY >= (c + len) % FLUSH_EVERY { 105 | stream1.flush().unwrap(); 106 | } 107 | 108 | if c < SEND_DELAY_NEAR && c + len > SEND_DELAY_NEAR { 109 | runtime_handle.sleep(Duration::from_secs(1)).await; 110 | } 111 | 112 | c += len; 113 | 114 | if c == END_POS { 115 | stream1.flush().unwrap(); 116 | break; 117 | } 118 | } 119 | 120 | let _ = a_done_send.send(stream1); 121 | } 122 | }); 123 | 124 | let (b_done_send, mut b_done) = oneshot::channel(); 125 | runtime.spawn({ 126 | let runtime_handle = runtime.handle(); 127 | async move { 128 | let mut recv_buffer = [0; 64]; 129 | let mut c = 0; 130 | 131 | loop { 132 | let len = stream2.read(&mut recv_buffer).await.unwrap(); 133 | for i in 0..len { 134 | if recv_buffer[i] != (c + i) as u8 { 135 | panic!(); 136 | } 137 | } 138 | 139 | if c < RECV_DELAY_NEAR && c + len >= RECV_DELAY_NEAR { 140 | runtime_handle.sleep(Duration::from_secs(2)).await; 141 | } 142 | 143 | c += len; 144 | 145 | if c == END_POS { 146 | break; 147 | } 148 | } 149 | 150 | let _ = b_done_send.send(stream2); 151 | } 152 | }); 153 | 154 | let mut a_done_stream = None; 155 | let mut b_done_stream = None; 156 | for _ in 0..100_000 { 157 | a_done_stream = a_done_stream.or_else(|| a_done.try_recv().unwrap()); 158 | b_done_stream = b_done_stream.or_else(|| b_done.try_recv().unwrap()); 159 | 160 | if a_done_stream.is_some() && b_done_stream.is_some() { 161 | return; 162 | } 163 | 164 | runtime.run_until_stalled(); 165 | runtime.advance_time(50); 166 | } 167 | 168 | panic!("didn't finish in time"); 169 | } 170 | -------------------------------------------------------------------------------- /tests/unreliable_bincode_channel.rs: -------------------------------------------------------------------------------- 1 | use futures::channel::oneshot; 2 | use serde::{Deserialize, Serialize}; 3 | 4 | use turbulence::{ 5 | buffer::BufferPacketPool, 6 | runtime::Spawn, 7 | spsc, 8 | unreliable_bincode_channel::UnreliableTypedChannel, 9 | unreliable_channel::{Settings, UnreliableChannel}, 10 | }; 11 | 12 | mod util; 13 | 14 | use self::util::{SimpleBufferPool, SimpleRuntime, SimpleRuntimeHandle}; 15 | 16 | #[test] 17 | fn test_unreliable_bincode_channel() { 18 | const SETTINGS: Settings = Settings { 19 | bandwidth: 512, 20 | burst_bandwidth: 256, 21 | }; 22 | 23 | let mut runtime = SimpleRuntime::new(); 24 | let packet_pool = BufferPacketPool::new(SimpleBufferPool(1200)); 25 | 26 | let (asend, arecv) = spsc::channel(8); 27 | let (bsend, brecv) = spsc::channel(8); 28 | 29 | let mut stream1 = UnreliableTypedChannel::new(UnreliableChannel::new( 30 | runtime.handle(), 31 | packet_pool.clone(), 32 | SETTINGS, 33 | bsend, 34 | arecv, 35 | )); 36 | let mut stream2 = UnreliableTypedChannel::new(UnreliableChannel::new( 37 | runtime.handle(), 38 | packet_pool.clone(), 39 | SETTINGS, 40 | asend, 41 | brecv, 42 | )); 43 | 44 | #[derive(Eq, PartialEq, Debug, Serialize, Deserialize)] 45 | struct MyMsg { 46 | a: u8, 47 | b: u8, 48 | c: u8, 49 | } 50 | 51 | async fn send( 52 | stream: &mut UnreliableTypedChannel< 53 | SimpleRuntimeHandle, 54 | BufferPacketPool, 55 | MyMsg, 56 | >, 57 | val: u8, 58 | len: u8, 59 | ) { 60 | for i in 0..len { 61 | stream 62 | .send(&MyMsg { 63 | a: val + i, 64 | b: val + 1 + i, 65 | c: val + 2 + i, 66 | }) 67 | .await 68 | .unwrap(); 69 | } 70 | stream.flush().await.unwrap(); 71 | } 72 | 73 | async fn recv( 74 | stream: &mut UnreliableTypedChannel< 75 | SimpleRuntimeHandle, 76 | BufferPacketPool, 77 | MyMsg, 78 | >, 79 | val: u8, 80 | len: u8, 81 | ) { 82 | for i in 0..len { 83 | assert_eq!( 84 | stream.recv().await.unwrap(), 85 | MyMsg { 86 | a: val + i, 87 | b: val + 1 + i, 88 | c: val + 2 + i, 89 | } 90 | ); 91 | } 92 | } 93 | 94 | let (a_done_send, mut a_done) = oneshot::channel(); 95 | runtime.spawn(async move { 96 | send(&mut stream1, 42, 5).await; 97 | recv(&mut stream1, 17, 80).await; 98 | send(&mut stream1, 4, 70).await; 99 | recv(&mut stream1, 25, 115).await; 100 | recv(&mut stream1, 0, 0).await; 101 | recv(&mut stream1, 0, 0).await; 102 | send(&mut stream1, 64, 100).await; 103 | send(&mut stream1, 0, 0).await; 104 | send(&mut stream1, 64, 100).await; 105 | send(&mut stream1, 0, 0).await; 106 | send(&mut stream1, 0, 0).await; 107 | recv(&mut stream1, 0, 0).await; 108 | recv(&mut stream1, 99, 6).await; 109 | send(&mut stream1, 72, 40).await; 110 | send(&mut stream1, 82, 50).await; 111 | send(&mut stream1, 92, 60).await; 112 | let _ = a_done_send.send(stream1); 113 | }); 114 | 115 | let (b_done_send, mut b_done) = oneshot::channel(); 116 | runtime.spawn(async move { 117 | recv(&mut stream2, 42, 5).await; 118 | send(&mut stream2, 17, 80).await; 119 | recv(&mut stream2, 4, 70).await; 120 | send(&mut stream2, 25, 115).await; 121 | send(&mut stream2, 0, 0).await; 122 | send(&mut stream2, 0, 0).await; 123 | recv(&mut stream2, 64, 100).await; 124 | recv(&mut stream2, 0, 0).await; 125 | recv(&mut stream2, 64, 100).await; 126 | recv(&mut stream2, 0, 0).await; 127 | recv(&mut stream2, 0, 0).await; 128 | send(&mut stream2, 0, 0).await; 129 | send(&mut stream2, 99, 6).await; 130 | recv(&mut stream2, 72, 40).await; 131 | recv(&mut stream2, 82, 50).await; 132 | recv(&mut stream2, 92, 60).await; 133 | let _ = b_done_send.send(stream2); 134 | }); 135 | 136 | let mut a_done_stream = None; 137 | let mut b_done_stream = None; 138 | for _ in 0..100_000 { 139 | a_done_stream = a_done_stream.or_else(|| a_done.try_recv().unwrap()); 140 | b_done_stream = b_done_stream.or_else(|| b_done.try_recv().unwrap()); 141 | 142 | if a_done_stream.is_some() && b_done_stream.is_some() { 143 | return; 144 | } 145 | 146 | runtime.run_until_stalled(); 147 | runtime.advance_time(50); 148 | } 149 | 150 | panic!("didn't finish in time"); 151 | } 152 | -------------------------------------------------------------------------------- /tests/unreliable_channel.rs: -------------------------------------------------------------------------------- 1 | use futures::channel::oneshot; 2 | 3 | use turbulence::{ 4 | buffer::BufferPacketPool, 5 | runtime::Spawn, 6 | spsc, 7 | unreliable_channel::{Settings, UnreliableChannel}, 8 | }; 9 | 10 | mod util; 11 | 12 | use self::util::{SimpleBufferPool, SimpleRuntime, SimpleRuntimeHandle}; 13 | 14 | #[test] 15 | fn test_unreliable_channel() { 16 | const SETTINGS: Settings = Settings { 17 | bandwidth: 512, 18 | burst_bandwidth: 256, 19 | }; 20 | 21 | let mut runtime = SimpleRuntime::new(); 22 | let packet_pool = BufferPacketPool::new(SimpleBufferPool(1200)); 23 | 24 | let (asend, arecv) = spsc::channel(8); 25 | let (bsend, brecv) = spsc::channel(8); 26 | 27 | let mut stream1 = UnreliableChannel::new( 28 | runtime.handle(), 29 | packet_pool.clone(), 30 | SETTINGS, 31 | bsend, 32 | arecv, 33 | ); 34 | let mut stream2 = UnreliableChannel::new( 35 | runtime.handle(), 36 | packet_pool.clone(), 37 | SETTINGS, 38 | asend, 39 | brecv, 40 | ); 41 | 42 | async fn send( 43 | stream: &mut UnreliableChannel>, 44 | val: u8, 45 | len: usize, 46 | ) { 47 | let msg1 = vec![val; len]; 48 | stream.send(&msg1).await.unwrap(); 49 | stream.flush().await.unwrap(); 50 | } 51 | 52 | async fn recv( 53 | stream: &mut UnreliableChannel>, 54 | val: u8, 55 | len: usize, 56 | ) { 57 | assert_eq!(stream.recv().await.unwrap(), vec![val; len].as_slice()); 58 | } 59 | 60 | let (a_done_send, mut a_done) = oneshot::channel(); 61 | runtime.spawn(async move { 62 | send(&mut stream1, 42, 5).await; 63 | recv(&mut stream1, 17, 800).await; 64 | send(&mut stream1, 4, 700).await; 65 | recv(&mut stream1, 25, 1150).await; 66 | recv(&mut stream1, 0, 0).await; 67 | recv(&mut stream1, 0, 0).await; 68 | send(&mut stream1, 64, 1000).await; 69 | send(&mut stream1, 0, 0).await; 70 | send(&mut stream1, 64, 1000).await; 71 | send(&mut stream1, 0, 0).await; 72 | send(&mut stream1, 0, 0).await; 73 | recv(&mut stream1, 0, 0).await; 74 | recv(&mut stream1, 99, 64).await; 75 | send(&mut stream1, 72, 400).await; 76 | send(&mut stream1, 82, 500).await; 77 | send(&mut stream1, 92, 600).await; 78 | let _ = a_done_send.send(stream1); 79 | }); 80 | 81 | let (b_done_send, mut b_done) = oneshot::channel(); 82 | runtime.spawn(async move { 83 | recv(&mut stream2, 42, 5).await; 84 | send(&mut stream2, 17, 800).await; 85 | recv(&mut stream2, 4, 700).await; 86 | send(&mut stream2, 25, 1150).await; 87 | send(&mut stream2, 0, 0).await; 88 | send(&mut stream2, 0, 0).await; 89 | recv(&mut stream2, 64, 1000).await; 90 | recv(&mut stream2, 0, 0).await; 91 | recv(&mut stream2, 64, 1000).await; 92 | recv(&mut stream2, 0, 0).await; 93 | recv(&mut stream2, 0, 0).await; 94 | send(&mut stream2, 0, 0).await; 95 | send(&mut stream2, 99, 64).await; 96 | recv(&mut stream2, 72, 400).await; 97 | recv(&mut stream2, 82, 500).await; 98 | recv(&mut stream2, 92, 600).await; 99 | let _ = b_done_send.send(stream2); 100 | }); 101 | 102 | let mut a_done_stream = None; 103 | let mut b_done_stream = None; 104 | for _ in 0..100_000 { 105 | a_done_stream = a_done_stream.or_else(|| a_done.try_recv().unwrap()); 106 | b_done_stream = b_done_stream.or_else(|| b_done.try_recv().unwrap()); 107 | 108 | if a_done_stream.is_some() && b_done_stream.is_some() { 109 | return; 110 | } 111 | 112 | runtime.run_until_stalled(); 113 | runtime.advance_time(50); 114 | } 115 | 116 | panic!("didn't finish in time"); 117 | } 118 | -------------------------------------------------------------------------------- /tests/util/mod.rs: -------------------------------------------------------------------------------- 1 | #![allow(unused)] 2 | 3 | use std::{ 4 | future::Future, 5 | ops::Deref, 6 | pin::Pin, 7 | sync::{Arc, Mutex}, 8 | task::{Context, Poll, Waker}, 9 | time::Duration, 10 | }; 11 | 12 | use futures::{ 13 | channel::mpsc, 14 | future::{self, BoxFuture}, 15 | stream::{self, FuturesUnordered}, 16 | task::noop_waker, 17 | SinkExt, Stream, StreamExt, 18 | }; 19 | use rand::Rng; 20 | 21 | use turbulence::{ 22 | buffer::BufferPool, 23 | packet::{Packet, PacketPool}, 24 | packet_multiplexer::{MuxPacket, MuxPacketPool}, 25 | runtime::{Spawn, Timer}, 26 | spsc, 27 | }; 28 | 29 | #[derive(Debug, Copy, Clone)] 30 | pub struct SimpleBufferPool(pub usize); 31 | 32 | impl BufferPool for SimpleBufferPool { 33 | type Buffer = Box<[u8]>; 34 | 35 | fn capacity(&self) -> usize { 36 | self.0 37 | } 38 | 39 | fn acquire(&mut self) -> Self::Buffer { 40 | vec![0; self.0].into_boxed_slice() 41 | } 42 | } 43 | 44 | struct TimeState { 45 | time: u64, 46 | queue: Vec<(u64, Waker)>, 47 | } 48 | 49 | type IncomingTasks = Mutex>>; 50 | 51 | struct HandleInner { 52 | time_state: Mutex, 53 | incoming_tasks: IncomingTasks, 54 | } 55 | 56 | pub struct SimpleRuntime { 57 | pool: FuturesUnordered>, 58 | handle: SimpleRuntimeHandle, 59 | } 60 | 61 | #[derive(Clone)] 62 | pub struct SimpleRuntimeHandle(Arc); 63 | 64 | impl SimpleRuntime { 65 | pub fn new() -> Self { 66 | SimpleRuntime { 67 | pool: FuturesUnordered::new(), 68 | handle: SimpleRuntimeHandle(Arc::new(HandleInner { 69 | time_state: Mutex::new(TimeState { 70 | time: 0, 71 | queue: Vec::new(), 72 | }), 73 | incoming_tasks: IncomingTasks::default(), 74 | })), 75 | } 76 | } 77 | 78 | pub fn handle(&self) -> SimpleRuntimeHandle { 79 | self.handle.clone() 80 | } 81 | 82 | pub fn advance_time(&mut self, millis: u64) { 83 | let mut state = self.handle.0.time_state.lock().unwrap(); 84 | state.time += millis; 85 | 86 | let mut arrived = 0; 87 | for i in 0..state.queue.len() { 88 | if state.time >= state.queue[i].0 { 89 | arrived = i + 1; 90 | } else { 91 | break; 92 | } 93 | } 94 | 95 | for (_, waker) in state.queue.drain(0..arrived) { 96 | waker.wake(); 97 | } 98 | } 99 | 100 | pub fn run_until_stalled(&mut self) -> bool { 101 | let waker = noop_waker(); 102 | let mut cx = Context::from_waker(&waker); 103 | 104 | loop { 105 | { 106 | let mut incoming = self.handle.0.incoming_tasks.lock().unwrap(); 107 | for task in incoming.drain(..) { 108 | self.pool.push(task); 109 | } 110 | } 111 | 112 | let next = self.pool.poll_next_unpin(&mut cx); 113 | 114 | if self.handle.0.incoming_tasks.lock().unwrap().is_empty() { 115 | match next { 116 | Poll::Pending => return false, 117 | Poll::Ready(None) => return true, 118 | Poll::Ready(Some(())) => {} 119 | } 120 | } 121 | } 122 | } 123 | } 124 | 125 | impl Deref for SimpleRuntime { 126 | type Target = SimpleRuntimeHandle; 127 | 128 | fn deref(&self) -> &Self::Target { 129 | &self.handle 130 | } 131 | } 132 | 133 | async fn do_delay(state: Arc, duration: Duration) -> u64 { 134 | // Our timer requires manual advancing, so delays should never spawn arrived so we don't starve 135 | // the code that manually advances the time. 136 | let arrival = state.time_state.lock().unwrap().time + (duration.as_millis() as u64).max(1); 137 | future::poll_fn(move |cx| -> Poll { 138 | let mut state = state.time_state.lock().unwrap(); 139 | if state.time >= arrival { 140 | Poll::Ready(state.time) 141 | } else { 142 | let i = match state.queue.binary_search_by_key(&arrival, |(t, _)| *t) { 143 | Ok(i) => i, 144 | Err(i) => i, 145 | }; 146 | state.queue.insert(i, (arrival, cx.waker().clone())); 147 | Poll::Pending 148 | } 149 | }) 150 | .await 151 | } 152 | 153 | impl Spawn for SimpleRuntimeHandle { 154 | fn spawn + Send + 'static>(&self, f: F) { 155 | self.0.incoming_tasks.lock().unwrap().push(Box::pin(f)) 156 | } 157 | } 158 | 159 | impl Timer for SimpleRuntimeHandle { 160 | type Instant = u64; 161 | type Sleep = Pin + Send>>; 162 | 163 | fn now(&self) -> Self::Instant { 164 | self.0.time_state.lock().unwrap().time 165 | } 166 | 167 | fn duration_between(&self, earlier: Self::Instant, later: Self::Instant) -> Duration { 168 | Duration::from_millis(later - earlier) 169 | } 170 | 171 | fn sleep(&self, duration: Duration) -> Self::Sleep { 172 | let state = Arc::clone(&self.0); 173 | Box::pin(async move { 174 | do_delay(state, duration).await; 175 | }) 176 | } 177 | } 178 | 179 | #[derive(Clone, Copy)] 180 | pub struct LinkCondition { 181 | pub loss: f64, 182 | pub duplicate: f64, 183 | pub delay: Duration, 184 | pub jitter: Duration, 185 | } 186 | 187 | pub fn condition_link

( 188 | condition: LinkCondition, 189 | spawn: impl Spawn + Clone + 'static, 190 | timer: impl Timer + Clone + 'static, 191 | mut pool: P, 192 | mut rng: impl Rng + Send + 'static, 193 | mut sender: spsc::Sender, 194 | mut receiver: spsc::Receiver, 195 | ) where 196 | P: PacketPool + Send + 'static, 197 | P::Packet: Send, 198 | { 199 | // Hack to make implementing delayed packets easier 200 | let (delay_outgoing, mut delay_incoming) = mpsc::unbounded(); 201 | 202 | spawn.spawn(async move { 203 | while let Some(msg) = delay_incoming.next().await { 204 | if sender.send(msg).await.is_err() { 205 | break; 206 | } 207 | } 208 | }); 209 | 210 | spawn.spawn({ 211 | let spawn = spawn.clone(); 212 | async move { 213 | loop { 214 | match receiver.next().await { 215 | Some(packet) => { 216 | if rng.gen::() > condition.loss { 217 | if rng.gen::() <= condition.duplicate { 218 | spawn.spawn({ 219 | let timer = timer.clone(); 220 | let mut outgoing = delay_outgoing.clone(); 221 | let delay = Duration::from_secs_f64( 222 | condition.delay.as_secs_f64() 223 | + rng.gen::() * condition.jitter.as_secs_f64(), 224 | ); 225 | let mut dup_packet = pool.acquire(); 226 | dup_packet.extend(&packet[..]); 227 | async move { 228 | timer.sleep(delay).await; 229 | let _ = outgoing.send(dup_packet).await; 230 | } 231 | }); 232 | } 233 | 234 | spawn.spawn({ 235 | let timer = timer.clone(); 236 | let mut outgoing = delay_outgoing.clone(); 237 | let delay = Duration::from_secs_f64( 238 | condition.delay.as_secs_f64() 239 | + rng.gen::() * condition.jitter.as_secs_f64(), 240 | ); 241 | async move { 242 | timer.sleep(delay).await; 243 | let _ = outgoing.send(packet).await; 244 | } 245 | }); 246 | } 247 | } 248 | None => break, 249 | } 250 | } 251 | } 252 | }); 253 | } 254 | --------------------------------------------------------------------------------