Repository: meqif/rust-utp Branch: main Commit: aad625717689 Files: 22 Total size: 167.2 KB Directory structure: gitextract_ilh0vthc/ ├── .gitignore ├── .travis.yml ├── CHANGELOG.md ├── COPYRIGHT ├── Cargo.toml ├── LICENSE-APACHE ├── LICENSE-MIT ├── README.md ├── appveyor.yml ├── benches/ │ ├── socket.rs │ └── stream.rs ├── examples/ │ ├── echo-server.rs │ └── utpcat.rs ├── src/ │ ├── bit_iterator.rs │ ├── error.rs │ ├── lib.rs │ ├── packet.rs │ ├── socket.rs │ ├── stream.rs │ ├── time.rs │ └── util.rs └── tests/ └── stream.rs ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ doc target *.swp Cargo.lock ================================================ FILE: .travis.yml ================================================ language: rust cache: cargo sudo: false addons: apt: packages: - libcurl4-openssl-dev - libelf-dev - libdw-dev rust: - nightly - beta - stable matrix: allow_failures: - rust: nightly before_script: - pip install 'travis-cargo<0.2' --user && export PATH=$HOME/.local/bin:$PATH after_success: | export RUSTFLAGS="$RUSTFLAGS -C link-dead-code" && travis-cargo --only stable doc && travis-cargo --only stable doc-upload && wget https://github.com/SimonKagstrom/kcov/archive/master.tar.gz && tar xzf master.tar.gz && mv kcov-master kcov cd kcov && mkdir build && cd build && cmake .. && make && cd ../.. && for file in target/debug/{utp,stream}-*; do mkdir -p "target/cov/$(basename $file)"; kcov/build/src/kcov --exclude-pattern=/.cargo,/usr/lib --verify "target/cov/$(basename $file)" "$file"; done && bash <(curl -s https://codecov.io/bash) && echo "Uploaded code coverage" env: global: secure: cqq4PpUsrmCNLbWrmkkuf/SaCKET0+QN5w0lXmuOndBES5C+m/aR417T3Pb+7PR4gqibf47eSXgaVCQa64eZAI5PjgXrdZ7FtPRu/mgcsgcgiVrSUz5C/KSMsmp876Gl67csjCZ6SZXJ3YC0/Jh3jiJLiRt9Giqzn/s1v15j/CY= ================================================ FILE: CHANGELOG.md ================================================ # Change Log ## [0.6.3] ### Added - Added `peer_fn` method to UtpSocket. ### Fixed - Fixed arithmetic operation overflow when calculating the delay between peers. - Unconnected sockets and streams no longer send fast resend requests before failing. ## [0.6.2] ### Fixed - Fixed Windows build. ## [0.6.1] ### Added - Packets are resent if no acknowledgment is received before timeout. - Sockets time out after too many retransmissions (configurable), returning an error. ### Fixed - Socket creation no longer fails with arithmetic overflow when generating a random connection identifier. - SACK extension generation no longer fails with arithmetic overflow. - Resending lost packets no longer floods the connection. - Fixed packet extension encoding. - Many protocol bug fixes. - Fixed warning about Sized in trait on rustc 1.4.0-nightly (10d69db0a 2015-08-23) (RFC 1214 fallout) ## [0.6.0] ### Added - Implemented the `Deref` trait for easy conversion from `UtpStream` instances into the underlying `UtpSocket`. ### Changed - `UtpSocket::connect` is now a function instead of a method on a `UtpSocket` instance (i.e., it doesn't require a socket to be called). ## [0.5.1] ### Added - Added `local_addr` for both `UtpSocket` and `UtpStream`. ## [0.5.0] ### Added - Added `local_addr` for both `UtpSocket` and `UtpStream`. - Added the `Into` trait for easy conversion from `UtpSocket` instances into `UtpStream`. ### Changed - `UtpListener::accept` now returns both the new socket and the remote peer's address (`Result`), similarly to `TcpListener`. - `UtpListener::incoming` now also returns the remote peer's address, similarly to `accept` but unlike `TcpListener::incoming`. ## [0.4.0] ### Added - Added `UtpListener` (similar to [`TcpListener`][http://doc.rust-lang.org/std/net/struct.TcpListener.html]). ## [0.3.1] ### Fixed - Removed assertions about `off_target`, which were killing innocent connections. ## [0.3.0] ### Fixed - Fixed bug when adjusting congestion window caused by miscalculating the delay between peers. - Fixed bug where missing packets weren't being re-sent after sending a FIN. - Fixed bug where a stream wouldn't bind to an address of the appropriate family when the remote peer had an IPv6 address. - Fixed bug where the congestion window would only shrink when packet loss was detected and not on delay changes. ### Changed - A call to `UtpStream::write` or `UtpSocket::send_to` no longer blocks until every packet is acknowledged. To force the old, slower behaviour, call `flush` after the usual calls (usually you won't need to do this, as the socket/stream is flushed on close/drop). ## [0.2.8] ### Fixed - Fixed bug where extensions could be skipped when parsing a packet. - Improved reliability of packet parsing. ## [0.2.7] ### Fixed - Fixed compilation errors in 1.0.0-beta.2 ### Changed - Improved resilience to errors --- receiving an invalid packet no longer leads to a panic - Sockets with established connections refuse new connections ## [0.2.6] No functional changes. ### Changed - Removed stability attributes. - Removed an unnecessary partial clone when handling a received packet. ## [0.2.5] ### Changed - Dropping an `UtpSocket` (or a wrapping struct like `UtpStream`) properly closes open connections. ## [0.2.4] Improved performance encoding and decoding packets. ## [0.2.3] ### Fixed - Now the crate builds in both the latest nightly and 1.0.0-beta. ## [0.2.2] No functional changes, mostly just changes to conform to changes in the Rust API. ## [0.2.1] ### Changed - Updated the `rand` dependency because the previous one didn't build on the latest Rust nightly. ### Fixed - Some `UtpStream` tests were failing because of improperly sized buffers. ## [0.2.0] This release is now compatible with the 2015-03-28 nightly of the Rust compiler. Some things changed during the migration to the new `std::net` API and performance is now much lower. It might take me a while to come up with performance improvements and a replacement for the lost `set_timeout` method in `UdpSocket`. ### Changed - Updated example in README. - `UtpStream` and `UtpSocket` now accept variables implementing the `ToSocketAddrs` trait, like `UdpSocket` in the standard library. - Reading from a socket now returns `Result<(usize, SocketAddr)>`. - Reading from a stream now returns `Result`. - Reading from a closed socket/stream now returns `Ok((0, remote_peer))`/`Ok(0)` instead of `Err(Closed)`. ### Added - `UtpStream` now implements the `Read` and `Write` traits. ### Removed - The `Reader` and `Writer` traits were removed, in accordance to the recent IO reform in Rust. - Support for connection timeouts were removed, which may impact packet loss handling in some cases. ================================================ FILE: COPYRIGHT ================================================ This project is dual-licensed under the terms of the MIT and Apache (version 2.0) licenses. ================================================ FILE: Cargo.toml ================================================ [package] authors = ["Ricardo Martins "] description = "A µTP (Micro/uTorrent Transport Library) library implemented in Rust" documentation = "http://meqif.github.io/rust-utp" homepage = "https://github.com/meqif/rust-utp" keywords = ["utp", "networking", "protocol", "transport"] license = "MIT/Apache-2.0" name = "utp" readme = "README.md" repository = "https://github.com/meqif/rust-utp" version = "0.7.1-pre" edition = "2018" [badges] maintenance = { status = "experimental" } [dependencies] log = "0.4.14" num-traits = "0.2.14" rand = "0.8.3" [dev-dependencies] quickcheck = "1.0.3" env_logger = "0.8.3" [lib] name = "utp" [features] unstable = [] ================================================ FILE: LICENSE-APACHE ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "{}" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright {yyyy} {name of copyright owner} Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ================================================ FILE: LICENSE-MIT ================================================ The MIT License (MIT) Copyright (c) 2014 Ricardo Martins Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: README.md ================================================ # rust-utp [![Crate Version](https://img.shields.io/crates/v/utp.svg?style=flat)](https://crates.io/crates/utp) [![Build Status](https://img.shields.io/travis/meqif/rust-utp.svg?style=flat)](http://travis-ci.org/meqif/rust-utp) [![Windows Build Status](https://ci.appveyor.com/api/projects/status/q38b38fendqat8o6?svg=true)](https://ci.appveyor.com/project/meqif/rust-utp) [![codecov](https://codecov.io/gh/meqif/rust-utp/branch/master/graph/badge.svg)](https://codecov.io/gh/meqif/rust-utp) [![Dependency Status](https://dependencyci.com/github/meqif/rust-utp/badge)](https://dependencyci.com/github/meqif/rust-utp) ![Maintenance: experimental](https://img.shields.io/badge/maintenance-experimental-red.svg) A [Micro Transport Protocol](http://www.bittorrent.org/beps/bep_0029.html) library implemented in Rust. [API documentation](http://meqif.github.io/rust-utp/) ## Overview The Micro Transport Protocol is a reliable transport protocol built over UDP. Its congestion control algorithm is [LEDBAT](http://tools.ietf.org/html/rfc6817), which tries to use as much unused bandwidth as it can but readily yields to competing flows, making it useful for bulk transfers without introducing congestion in the network. The current implementation is somewhat incomplete, lacking a complete implementation of congestion control. However, it does support packet loss detection (except by timeout) the Selective Acknowledgment extension, handles unordered and duplicate packets and presents a stream interface (`UtpStream`). ## Usage To use `utp`, add this to your `Cargo.toml`: ```toml [dependencies] utp = "*" ``` Then, import it in your crate root or wherever you need it: ```rust extern crate utp; ``` ## Examples The simplest example program would be: ```rust extern crate utp; use utp::UtpStream; use std::io::Write; fn main() { // Connect to an hypothetical local server running on port 8080 let addr = "127.0.0.1:8080"; let mut stream = UtpStream::connect(addr).expect("Error connecting to remote peer"); // Send a string stream.write("Hi there!".as_bytes()).expect("Write failed"); // Close the stream stream.close().expect("Error closing connection"); } ``` Check out the files under the "examples" directory for more example programs, or run them with `cargo run --example `. ## Roadmap - [x] congestion control - [x] proper connection closing - [x] handle both RST and FIN - [x] send FIN on close - [x] automatically send FIN on `drop` if not already closed - [x] sending RST on mismatch - [x] setters and getters that hide header field endianness conversion - [x] SACK extension - [x] handle packet loss - [x] send triple-ACK to re-request lost packet (fast resend request) - [x] rewind send window and resend in reply to triple-ACK (fast resend) - [x] resend packet on ACK timeout - [x] stream interface - [x] handle unordered packets - [x] duplicate packet handling - [x] listener abstraction - [x] incoming connections iterator - [x] time out connection after too many retransmissions - [ ] path MTU discovery ## License This library is distributed under similar terms to Rust: dual licensed under the MIT license and the Apache license (version 2.0). See LICENSE-APACHE, LICENSE-MIT, and COPYRIGHT for details. ================================================ FILE: appveyor.yml ================================================ install: - ps: Start-FileDownload 'https://static.rust-lang.org/dist/rust-nightly-i686-pc-windows-gnu.exe' - rust-nightly-i686-pc-windows-gnu.exe /VERYSILENT /NORESTART /DIR="C:\Program Files (x86)\Rust" - SET PATH=%PATH%;C:\Program Files (x86)\Rust\bin - SET PATH=%PATH%;C:\MinGW\bin - rustc -V - cargo -V - git submodule update --init --recursive build: false test_script: - cargo test --verbose ================================================ FILE: benches/socket.rs ================================================ #![feature(test)] extern crate test; extern crate utp; use std::sync::Arc; use std::thread; use test::Bencher; use utp::UtpSocket; macro_rules! iotry { ($e:expr) => { match $e { Ok(e) => e, Err(e) => panic!("{}", e), } }; } fn next_test_port() -> u16 { use std::sync::atomic::{AtomicUsize, Ordering}; static NEXT_OFFSET: AtomicUsize = AtomicUsize::new(0); const BASE_PORT: u16 = 9600; BASE_PORT + NEXT_OFFSET.fetch_add(1, Ordering::Relaxed) as u16 } fn next_test_ip4<'a>() -> (&'a str, u16) { ("127.0.0.1", next_test_port()) } #[bench] fn bench_connection_setup_and_teardown(b: &mut Bencher) { let server_addr = next_test_ip4(); let mut buf = [0; 1500]; b.iter(|| { let mut server = iotry!(UtpSocket::bind(server_addr)); thread::spawn(move || { let mut client = iotry!(UtpSocket::connect(server_addr)); iotry!(client.close()); }); loop { match server.recv_from(&mut buf) { Ok((0, _src)) => break, Ok(_) => (), Err(e) => panic!("{}", e), } } iotry!(server.close()); }); } #[bench] fn bench_transfer_one_packet(b: &mut Bencher) { let len = 1024; let server_addr = next_test_ip4(); let mut buf = [0; 1500]; let data = (0..len).map(|x| x as u8).collect::>(); let data_arc = Arc::new(data); b.iter(|| { let data = data_arc.clone(); let mut server = iotry!(UtpSocket::bind(server_addr)); thread::spawn(move || { let mut client = iotry!(UtpSocket::connect(server_addr)); iotry!(client.send_to(&data[..])); iotry!(client.close()); }); loop { match server.recv_from(&mut buf) { Ok((0, _src)) => break, Ok(_) => (), Err(e) => panic!("{}", e), } } iotry!(server.close()); }); b.bytes = len as u64; } #[bench] fn bench_transfer_one_megabyte(b: &mut Bencher) { let len = 1024 * 1024; let server_addr = next_test_ip4(); let mut buf = [0; 1500]; let data = (0..len).map(|x| x as u8).collect::>(); let data_arc = Arc::new(data); b.iter(|| { let data = data_arc.clone(); let mut server = iotry!(UtpSocket::bind(server_addr)); thread::spawn(move || { let mut client = iotry!(UtpSocket::connect(server_addr)); iotry!(client.send_to(&data[..])); iotry!(client.close()); }); loop { match server.recv_from(&mut buf) { Ok((0, _src)) => break, Ok(_) => (), Err(e) => panic!("{}", e), } } iotry!(server.close()); }); b.bytes = len as u64; } ================================================ FILE: benches/stream.rs ================================================ #![feature(test)] extern crate test; extern crate utp; use std::io::{Read, Write}; use std::sync::Arc; use std::thread; use test::Bencher; use utp::UtpStream; macro_rules! iotry { ($e:expr) => { match $e { Ok(e) => e, Err(e) => panic!("{}", e), } }; } fn next_test_port() -> u16 { use std::sync::atomic::{AtomicUsize, Ordering}; static NEXT_OFFSET: AtomicUsize = AtomicUsize::new(0); const BASE_PORT: u16 = 9600; BASE_PORT + NEXT_OFFSET.fetch_add(1, Ordering::Relaxed) as u16 } fn next_test_ip4<'a>() -> (&'a str, u16) { ("127.0.0.1", next_test_port()) } #[bench] fn bench_connection_setup_and_teardown(b: &mut Bencher) { let server_addr = next_test_ip4(); let mut received = vec![]; b.iter(|| { let mut server = iotry!(UtpStream::bind(server_addr)); thread::spawn(move || { let mut client = iotry!(UtpStream::connect(server_addr)); iotry!(client.close()); }); iotry!(server.read_to_end(&mut received)); iotry!(server.close()); }); } #[bench] fn bench_transfer_one_packet(b: &mut Bencher) { let len = 1024; let server_addr = next_test_ip4(); let data = (0..len).map(|x| x as u8).collect::>(); let data_arc = Arc::new(data); let mut received = Vec::with_capacity(len); b.iter(|| { let data = data_arc.clone(); let mut server = iotry!(UtpStream::bind(server_addr)); thread::spawn(move || { let mut client = iotry!(UtpStream::connect(server_addr)); iotry!(client.write(&data[..])); iotry!(client.close()); }); iotry!(server.read_to_end(&mut received)); iotry!(server.close()); }); b.bytes = len as u64; } #[bench] fn bench_transfer_one_megabyte(b: &mut Bencher) { let len = 1024 * 1024; let server_addr = next_test_ip4(); let data = (0..len).map(|x| x as u8).collect::>(); let data_arc = Arc::new(data); let mut received = Vec::with_capacity(len); b.iter(|| { let data = data_arc.clone(); let mut server = iotry!(UtpStream::bind(server_addr)); thread::spawn(move || { let mut client = iotry!(UtpStream::connect(server_addr)); iotry!(client.write(&data[..])); iotry!(client.close()); }); iotry!(server.read_to_end(&mut received)); iotry!(server.close()); }); b.bytes = len as u64; } ================================================ FILE: examples/echo-server.rs ================================================ use env_logger; use std::thread; use utp::{UtpListener, UtpSocket}; fn handle_client(mut s: UtpSocket) { let mut buf = [0; 1500]; // Reply to a data packet with its own payload, then end the connection match s.recv_from(&mut buf) { Ok((nread, src)) => { println!("<= [{}] {:?}", src, &buf[..nread]); let _ = s.send_to(&buf[..nread]); } Err(e) => println!("{}", e), } } fn main() { // Start logger env_logger::init(); // Create a listener let addr = "127.0.0.1:8080"; let listener = UtpListener::bind(addr).expect("Error binding listener"); for connection in listener.incoming() { // Spawn a new handler for each new connection match connection { Ok((socket, _src)) => { thread::spawn(move || handle_client(socket)); } _ => (), } } } ================================================ FILE: examples/utpcat.rs ================================================ //! Implementation of a simple uTP client and server. use env_logger; use std::process; fn usage() -> ! { println!("Usage: utp [-s|-c]
"); process::exit(1); } fn main() { use std::io::{stderr, stdin, stdout, Read, Write}; use utp::UtpStream; // This example may run in either server or client mode. // Using an enum tends to make the code cleaner and easier to read. enum Mode { Server, Client, } // Start logging env_logger::init(); // Fetch arguments let mut args = std::env::args(); // Skip program name args.next(); // Parse the mode argument let mode: Mode = match args.next() { Some(ref s) if s == "-s" => Mode::Server, Some(ref s) if s == "-c" => Mode::Client, _ => usage(), }; // Parse the address argument or use a default if none is provided let addr = match (args.next(), args.next()) { (None, None) => "127.0.0.1:8080".to_owned(), (Some(ip), Some(port)) => format!("{}:{}", ip, port), _ => usage(), }; let addr: &str = &addr; match mode { Mode::Server => { // Create a listening stream let mut stream = UtpStream::bind(addr).expect("Error binding stream"); let mut writer = stdout(); let _ = writeln!(&mut stderr(), "Serving on {}", addr); // Create a reasonably sized buffer let mut payload = vec![0; 1024 * 1024]; // Wait for a new connection and print the received data to stdout. // Reading and printing chunks like this feels more interactive than trying to read // everything with `read_to_end` and avoids resizing the buffer multiple times. loop { match stream.read(&mut payload) { Ok(0) => break, Ok(read) => writer .write(&payload[..read]) .expect("Error writing to stdout"), Err(e) => panic!("{}", e), }; } } Mode::Client => { // Create a stream and try to connect to the remote address let mut stream = UtpStream::connect(addr).expect("Error connecting to remote peer"); let mut reader = stdin(); // Create a reasonably sized buffer let mut payload = vec![0; 1024 * 1024]; // Read from stdin and send it to the remote server. // Once again, reading and sending small chunks like this avoids having to read the // entire input (which may be endless!) before starting to send, unlike what would // happen if we were to use `read_to_end` on `reader`. loop { match reader.read(&mut payload) { Ok(0) => break, Ok(read) => stream .write(&payload[..read]) .expect("Error writing to stream"), Err(e) => { stream.close().expect("Error closing stream"); panic!("{:?}", e); } }; } // Explicitly close the stream. stream.close().expect("Error closing stream"); } } } ================================================ FILE: src/bit_iterator.rs ================================================ // How many bits in a `u8` const U8BITS: usize = 8; /// Lazy iterator over bits of a vector of bytes, starting with the LSB /// (least-significat bit) of the first element of the vector. pub struct BitIterator<'a> { object: &'a [u8], next_index: usize, end_index: usize, } impl<'a> BitIterator<'a> { /// Creates an iterator from a vector of bytes. Each byte becomes eight bits, with the least /// significant bits coming first. pub fn from_bytes(obj: &'a [u8]) -> BitIterator<'_> { BitIterator { object: obj, next_index: 0, end_index: obj.len() * U8BITS, } } /// Returns the number of ones in the binary representation of the underlying object. pub fn count_ones(&self) -> u32 { self.object.iter().fold(0, |acc, bv| acc + bv.count_ones()) } } impl<'a> Iterator for BitIterator<'a> { type Item = bool; fn next(&mut self) -> Option { if self.next_index != self.end_index { let (byte_index, bit_index) = (self.next_index / U8BITS, self.next_index % U8BITS); let bit = self.object[byte_index] >> bit_index & 0x1; self.next_index += 1; Some(bit == 0x1) } else { None } } fn size_hint(&self) -> (usize, Option) { (self.end_index, Some(self.end_index)) } } impl<'a> ExactSizeIterator for BitIterator<'a> {} #[test] fn test_iterator() { let bytes = vec![0xCA, 0xFE]; let expected_bits = vec![0, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1]; for (i, bit) in BitIterator::from_bytes(&bytes).enumerate() { println!("{} == {}", bit, expected_bits[i] == 1); assert_eq!(bit, expected_bits[i] == 1); } } ================================================ FILE: src/error.rs ================================================ use std::error::Error; use std::fmt; use std::io::{self, ErrorKind}; #[derive(Debug)] pub enum SocketError { ConnectionClosed, ConnectionReset, ConnectionTimedOut, InvalidAddress, InvalidReply, NotConnected, Other(String), } impl Error for SocketError { fn description(&self) -> &str { use self::SocketError::*; match *self { ConnectionClosed => "The socket is closed", ConnectionReset => "Connection reset by remote peer", ConnectionTimedOut => "Connection timed out", InvalidAddress => "Invalid address", InvalidReply => "The remote peer sent an invalid reply", NotConnected => "The socket is not connected", Other(ref s) => s, } } } impl fmt::Display for SocketError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{:?}", &self) } } impl From for io::Error { fn from(error: SocketError) -> io::Error { use self::SocketError::*; let kind = match error { ConnectionClosed | NotConnected => ErrorKind::NotConnected, ConnectionReset => ErrorKind::ConnectionReset, ConnectionTimedOut => ErrorKind::TimedOut, InvalidAddress => ErrorKind::InvalidInput, InvalidReply => ErrorKind::ConnectionRefused, Other(_) => ErrorKind::Other, }; io::Error::new(kind, error.to_string()) } } #[derive(Debug)] pub enum ParseError { InvalidExtensionLength, InvalidPacketLength, InvalidPacketType(u8), UnsupportedVersion, } impl fmt::Display for ParseError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{:?}", &self) } } impl Error for ParseError { fn description(&self) -> &str { use self::ParseError::*; match *self { InvalidExtensionLength => "Invalid extension length (must be a non-zero multiple of 4)", InvalidPacketLength => "The packet is too small", InvalidPacketType(_) => "Invalid packet type", UnsupportedVersion => "Unsupported packet version", } } } impl From for io::Error { fn from(error: ParseError) -> io::Error { io::Error::new(ErrorKind::Other, error.to_string()) } } ================================================ FILE: src/lib.rs ================================================ //! Implementation of the [Micro Transport Protocol][spec]. //! //! This library provides both a socket interface (`UtpSocket`) and a stream interface //! (`UtpStream`). //! I recommend that you use `UtpStream`, as it implements the `Read` and `Write` //! traits we all know (and love) from `std::io`, which makes it generally easier to work with than //! `UtpSocket`. //! //! [spec]: http://www.bittorrent.org/beps/bep_0029.html //! //! # Installation //! //! Ensure your `Cargo.toml` contains: //! //! ```toml //! [dependencies] //! utp = "*" //! ``` //! //! # Examples //! //! ```no_run //! extern crate utp; //! //! use utp::UtpStream; //! use std::io::Write; //! //! fn main() { //! // Connect to an hypothetical local server running on port 8080 //! let addr = "127.0.0.1:8080"; //! let mut stream = UtpStream::connect(addr).expect("Error connecting to remote peer"); //! //! // Send a string //! stream.write("Hi there!".as_bytes()).expect("Write failed"); //! //! // Close the stream //! stream.close().expect("Error closing connection"); //! } //! ``` //! //! Note that you can easily convert a socket to a stream using the `Into` trait, like so: //! //! ```no_run //! # use utp::{UtpStream, UtpSocket}; //! let socket = UtpSocket::bind("0.0.0.0:0").expect("Error binding socket"); //! let stream: UtpStream = socket.into(); //! ``` #![deny(missing_docs)] // Optional features #![cfg_attr(feature = "clippy", feature(plugin))] #![cfg_attr(feature = "clippy", plugin(clippy))] #![cfg_attr( feature = "clippy", allow( len_without_is_empty, doc_markdown, needless_return, transmute_ptr_to_ref ) )] #![cfg_attr(feature = "unstable", feature(test))] // Public API pub use crate::socket::UtpListener; pub use crate::socket::UtpSocket; pub use crate::stream::UtpStream; mod bit_iterator; mod error; mod packet; mod socket; mod stream; mod time; mod util; ================================================ FILE: src/packet.rs ================================================ #![allow(dead_code)] use crate::bit_iterator::BitIterator; use crate::error::ParseError; use crate::time::{Delay, Timestamp}; use std::fmt; pub const HEADER_SIZE: usize = 20; macro_rules! u8_to_unsigned_be { ($src:ident, $start:expr, $end:expr, $t:ty) => ({ (0 .. $end - $start + 1).rev().fold(0, |acc, i| acc | $src[$start+i] as $t << (i * 8)) }) } macro_rules! make_getter { ($name:ident, $t:ty, $m:ident) => { pub fn $name(&self) -> $t { let header = unsafe { &*(self.0.as_ptr() as *const PacketHeader) }; $m::from_be(header.$name) } }; } macro_rules! make_setter { ($fn_name:ident, $field:ident, $t: ty) => { pub fn $fn_name(&mut self, new: $t) { let mut header = unsafe { &mut *(self.0.as_mut_ptr() as *mut PacketHeader) }; header.$field = new.to_be(); } }; } /// Attempt to construct `Self` through conversion. /// /// Waiting for rust-lang/rust#33417 to become stable. pub trait TryFrom: Sized { type Err; fn try_from(_: T) -> Result; } #[derive(PartialEq, Eq, Debug)] pub enum PacketType { Data, // packet carries a data payload Fin, // signals the end of a connection State, // signals acknowledgment of a packet Reset, // forcibly terminates a connection Syn, // initiates a new connection with a peer } impl TryFrom for PacketType { type Err = ParseError; fn try_from(original: u8) -> Result { match original { 0 => Ok(PacketType::Data), 1 => Ok(PacketType::Fin), 2 => Ok(PacketType::State), 3 => Ok(PacketType::Reset), 4 => Ok(PacketType::Syn), n => Err(ParseError::InvalidPacketType(n)), } } } impl From for u8 { fn from(original: PacketType) -> u8 { match original { PacketType::Data => 0, PacketType::Fin => 1, PacketType::State => 2, PacketType::Reset => 3, PacketType::Syn => 4, } } } #[derive(PartialEq, Eq, Debug, Clone, Copy)] pub enum ExtensionType { None, SelectiveAck, Unknown(u8), } impl From for ExtensionType { fn from(original: u8) -> Self { match original { 0 => ExtensionType::None, 1 => ExtensionType::SelectiveAck, n => ExtensionType::Unknown(n), } } } impl From for u8 { fn from(original: ExtensionType) -> u8 { match original { ExtensionType::None => 0, ExtensionType::SelectiveAck => 1, ExtensionType::Unknown(n) => n, } } } #[derive(Clone)] pub struct Extension<'a> { ty: ExtensionType, pub data: &'a [u8], } impl<'a> Extension<'a> { pub fn len(&self) -> usize { self.data.len() } pub fn get_type(&self) -> ExtensionType { self.ty } pub fn iter(&self) -> BitIterator<'_> { BitIterator::from_bytes(self.data) } } #[repr(C)] struct PacketHeader { type_ver: u8, // type: u4, ver: u4 extension: u8, connection_id: u16, // Both timestamps are in microseconds timestamp: u32, timestamp_difference: u32, wnd_size: u32, seq_nr: u16, ack_nr: u16, } impl PacketHeader { /// Sets the type of packet to the specified type. pub fn set_type(&mut self, t: PacketType) { let version = 0x0F & self.type_ver; self.type_ver = u8::from(t) << 4 | version; } /// Returns the packet's type. pub fn get_type(&self) -> PacketType { PacketType::try_from(self.type_ver >> 4).unwrap() } /// Returns the packet's version. pub fn get_version(&self) -> u8 { self.type_ver & 0x0F } /// Returns the type of the first extension pub fn get_extension_type(&self) -> ExtensionType { self.extension.into() } } impl AsRef<[u8]> for PacketHeader { /// Returns the packet header as a slice of bytes. fn as_ref(&self) -> &[u8] { unsafe { &*(self as *const PacketHeader as *const [u8; HEADER_SIZE]) } } } impl<'a> TryFrom<&'a [u8]> for PacketHeader { type Err = ParseError; /// Reads a byte buffer and returns the corresponding packet header. /// It assumes the fields are in network (big-endian) byte order, /// preserving it. fn try_from(buf: &[u8]) -> Result { // Check length if buf.len() < HEADER_SIZE { return Err(ParseError::InvalidPacketLength); } // Check version if buf[0] & 0x0F != 1 { return Err(ParseError::UnsupportedVersion); } // Check packet type if let Err(e) = PacketType::try_from(buf[0] >> 4) { return Err(e); } Ok(PacketHeader { type_ver: buf[0], extension: buf[1], connection_id: u8_to_unsigned_be!(buf, 2, 3, u16), timestamp: u8_to_unsigned_be!(buf, 4, 7, u32), timestamp_difference: u8_to_unsigned_be!(buf, 8, 11, u32), wnd_size: u8_to_unsigned_be!(buf, 12, 15, u32), seq_nr: u8_to_unsigned_be!(buf, 16, 17, u16), ack_nr: u8_to_unsigned_be!(buf, 18, 19, u16), }) } } impl Default for PacketHeader { fn default() -> PacketHeader { PacketHeader { type_ver: u8::from(PacketType::Data) << 4 | 1, extension: 0, connection_id: 0, timestamp: 0, timestamp_difference: 0, wnd_size: 0, seq_nr: 0, ack_nr: 0, } } } pub struct Packet(Vec); impl AsRef<[u8]> for Packet { fn as_ref(&self) -> &[u8] { self.0.as_ref() } } impl Packet { /// Constructs a new, empty packet. pub fn new() -> Packet { Packet(PacketHeader::default().as_ref().to_owned()) } /// Constructs a new data packet with the given payload. pub fn with_payload(payload: &[u8]) -> Packet { let mut inner = Vec::with_capacity(HEADER_SIZE + payload.len()); let mut header = PacketHeader::default(); header.set_type(PacketType::Data); // inner.copy_from_slice(header.as_ref()); // inner.copy_from_slice(payload); inner.extend_from_slice(header.as_ref()); inner.extend_from_slice(payload); Packet(inner) } #[inline] pub fn set_type(&mut self, t: PacketType) { let header = unsafe { &mut *(self.0.as_mut_ptr() as *mut PacketHeader) }; header.set_type(t); } #[inline] pub fn get_type(&self) -> PacketType { let header = unsafe { &*(self.0.as_ptr() as *const PacketHeader) }; header.get_type() } pub fn get_version(&self) -> u8 { let header = unsafe { &*(self.0.as_ptr() as *const PacketHeader) }; header.get_version() } pub fn get_extension_type(&self) -> ExtensionType { let header = unsafe { &*(self.0.as_ptr() as *const PacketHeader) }; header.get_extension_type() } pub fn extensions(&self) -> ExtensionIterator<'_> { ExtensionIterator::new(self) } pub fn payload(&self) -> &[u8] { let mut index = HEADER_SIZE; let mut extension_type = ExtensionType::from(self.0[1]); // Consume known extensions and skip over unknown ones while index < self.0.len() && extension_type != ExtensionType::None { let len = self.0[index + 1] as usize; // Assume extension is valid because the bytes come from a (valid) Packet // ... extension_type = ExtensionType::from(self.0[index]); index += len + 2; } &self.0[index..] } pub fn timestamp(&self) -> Timestamp { let header = unsafe { &*(self.0.as_ptr() as *const PacketHeader) }; u32::from_be(header.timestamp).into() } pub fn set_timestamp(&mut self, timestamp: Timestamp) { let header = unsafe { &mut *(self.0.as_mut_ptr() as *mut PacketHeader) }; header.timestamp = u32::from(timestamp).to_be(); } pub fn timestamp_difference(&self) -> Delay { let header = unsafe { &*(self.0.as_ptr() as *const PacketHeader) }; u32::from_be(header.timestamp_difference).into() } pub fn set_timestamp_difference(&mut self, delay: Delay) { let header = unsafe { &mut *(self.0.as_mut_ptr() as *mut PacketHeader) }; header.timestamp_difference = u32::from(delay).to_be(); } make_getter!(seq_nr, u16, u16); make_getter!(ack_nr, u16, u16); make_getter!(connection_id, u16, u16); make_getter!(wnd_size, u32, u32); make_setter!(set_seq_nr, seq_nr, u16); make_setter!(set_ack_nr, ack_nr, u16); make_setter!(set_connection_id, connection_id, u16); make_setter!(set_wnd_size, wnd_size, u32); /// Sets Selective ACK field in packet header and adds appropriate data. /// /// The length of the SACK extension is expressed in bytes, which /// must be a multiple of 4 and at least 4. pub fn set_sack(&mut self, bv: Vec) { // The length of the SACK extension is expressed in bytes, which // must be a multiple of 4 and at least 4. assert!(bv.len() >= 4); assert_eq!(bv.len() % 4, 0); let mut index = HEADER_SIZE; let mut extension_type = ExtensionType::from(self.0[1]); // Set extension type in header if none is used, otherwise find and update the // "next extension type" marker in the last extension before payload if extension_type == ExtensionType::None { self.0[1] = ExtensionType::SelectiveAck.into(); } else { // Skip over all extensions until last, then modify its "next extension type" field and // add the new extension after it. // Consume known extensions and skip over unknown ones while index < self.0.len() && extension_type != ExtensionType::None { let len = self.0[index + 1] as usize; // No validity checks needed // ... extension_type = ExtensionType::from(self.0[index]); // Arrived at last extension if extension_type == ExtensionType::None { // Mark existence of an additional extension self.0[index] = ExtensionType::SelectiveAck.into(); } index += len + 2; } } // Insert the new extension into the packet's data. // The way this is currently done is potentially slower than the alternative of resizing the // underlying Vec, moving the payload forward and then writing the extension in the "new" // place before the payload. // Set the type of the following (non-existent) extension self.0.insert(index, ExtensionType::None.into()); // Set this extension's length self.0.insert(index + 1, bv.len() as u8); // Write this extension's data for (i, &value) in bv.iter().enumerate() { self.0.insert(index + 2 + i, value); } } pub fn len(&self) -> usize { self.0.len() } } impl<'a> TryFrom<&'a [u8]> for Packet { type Err = ParseError; /// Decodes a byte slice and construct the equivalent Packet. /// /// Note that this method makes no attempt to guess the payload size, saving /// all except the initial 20 bytes corresponding to the header as payload. /// It's the caller's responsibility to use an appropriately sized buffer. fn try_from(buf: &[u8]) -> Result { PacketHeader::try_from(buf) .and(check_extensions(buf)) .and(Ok(Packet(buf.to_owned()))) } } impl Clone for Packet { fn clone(&self) -> Packet { Packet(self.0.clone()) } } impl fmt::Debug for Packet { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("Packet") .field("type", &self.get_type()) .field("version", &self.get_version()) .field("extension", &self.get_extension_type()) .field("connection_id", &self.connection_id()) .field("timestamp", &self.timestamp()) .field("timestamp_difference", &self.timestamp_difference()) .field("wnd_size", &self.wnd_size()) .field("seq_nr", &self.seq_nr()) .field("ack_nr", &self.ack_nr()) .finish() } } pub struct ExtensionIterator<'a> { raw_bytes: &'a [u8], next_extension: ExtensionType, index: usize, } impl<'a> ExtensionIterator<'a> { fn new(packet: &'a Packet) -> Self { ExtensionIterator { raw_bytes: packet.as_ref(), next_extension: ExtensionType::from(packet.as_ref()[1]), index: HEADER_SIZE, } } } impl<'a> Iterator for ExtensionIterator<'a> { type Item = Extension<'a>; fn next(&mut self) -> Option { if self.next_extension == ExtensionType::None { None } else if self.index < self.raw_bytes.len() { let len = self.raw_bytes[self.index + 1] as usize; let extension_start = self.index + 2; let extension_end = extension_start + len; // Assume extension is valid because the bytes come from a (valid) Packet let extension = Extension { ty: self.next_extension, data: &self.raw_bytes[extension_start..extension_end], }; self.next_extension = self.raw_bytes[self.index].into(); self.index += len + 2; Some(extension) } else { None } } } /// Validate correctness of packet extensions, if any, in byte slice fn check_extensions(data: &[u8]) -> Result<(), ParseError> { if data.len() < HEADER_SIZE { return Err(ParseError::InvalidPacketLength); } let mut index = HEADER_SIZE; let mut extension_type = ExtensionType::from(data[1]); if data.len() == HEADER_SIZE && extension_type != ExtensionType::None { return Err(ParseError::InvalidExtensionLength); } // Consume known extensions and skip over unknown ones while index < data.len() && extension_type != ExtensionType::None { if data.len() < index + 2 { return Err(ParseError::InvalidPacketLength); } let len = data[index + 1] as usize; let extension_start = index + 2; let extension_end = extension_start + len; // Check validity of extension length: // - non-zero, // - multiple of 4, // - does not exceed packet length if len == 0 || len % 4 != 0 || extension_end > data.len() { return Err(ParseError::InvalidExtensionLength); } extension_type = ExtensionType::from(data[index]); index += len + 2; } // Check for pending extensions (early exit of previous loop) if extension_type != ExtensionType::None { return Err(ParseError::InvalidPacketLength); } Ok(()) } #[cfg(test)] mod tests { use crate::packet::PacketType::{Data, State}; use crate::packet::*; use crate::packet::{check_extensions, PacketHeader}; use crate::time::*; use quickcheck::{QuickCheck, TestResult}; #[test] fn test_packet_decode() { let buf = [ 0x21, 0x00, 0x41, 0xa8, 0x99, 0x2f, 0xd0, 0x2a, 0x9f, 0x4a, 0x26, 0x21, 0x00, 0x10, 0x00, 0x00, 0x3a, 0xf2, 0x6c, 0x79, ]; let packet = Packet::try_from(&buf); assert!(packet.is_ok()); let packet = packet.unwrap(); assert_eq!(packet.get_version(), 1); assert_eq!(packet.get_extension_type(), ExtensionType::None); assert_eq!(packet.get_type(), State); assert_eq!(packet.connection_id(), 16808); assert_eq!(packet.timestamp(), Timestamp(2570047530)); assert_eq!(packet.timestamp_difference(), Delay(2672436769)); assert_eq!(packet.wnd_size(), 2u32.pow(20)); assert_eq!(packet.seq_nr(), 15090); assert_eq!(packet.ack_nr(), 27769); assert_eq!(packet.len(), buf.len()); assert!(packet.payload().is_empty()); } #[test] fn test_decode_packet_with_extension() { let buf = [ 0x21, 0x01, 0x41, 0xa7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0xdc, 0xab, 0x53, 0x3a, 0xf5, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, ]; let packet = Packet::try_from(&buf); assert!(packet.is_ok()); let packet = packet.unwrap(); assert_eq!(packet.get_version(), 1); assert_eq!(packet.get_extension_type(), ExtensionType::SelectiveAck); assert_eq!(packet.get_type(), State); assert_eq!(packet.connection_id(), 16807); assert_eq!(packet.timestamp(), Timestamp(0)); assert_eq!(packet.timestamp_difference(), Delay(0)); assert_eq!(packet.wnd_size(), 1500); assert_eq!(packet.seq_nr(), 43859); assert_eq!(packet.ack_nr(), 15093); assert_eq!(packet.len(), buf.len()); assert!(packet.payload().is_empty()); let extensions: Vec> = packet.extensions().collect(); assert_eq!(extensions.len(), 1); assert_eq!(extensions[0].ty, ExtensionType::SelectiveAck); assert_eq!(extensions[0].data, &[0, 0, 0, 0]); assert_eq!(extensions[0].len(), extensions[0].data.len()); assert_eq!(extensions[0].len(), 4); // Reversible assert_eq!(packet.as_ref(), &buf); } #[test] fn test_packet_decode_with_missing_extension() { let buf = [ 0x21, 0x01, 0x41, 0xa8, 0x99, 0x2f, 0xd0, 0x2a, 0x9f, 0x4a, 0x26, 0x21, 0x00, 0x10, 0x00, 0x00, 0x3a, 0xf2, 0x6c, 0x79, ]; let packet = Packet::try_from(&buf); assert!(packet.is_err()); } #[test] fn test_packet_decode_with_malformed_extension() { let buf = [ 0x21, 0x01, 0x41, 0xa8, 0x99, 0x2f, 0xd0, 0x2a, 0x9f, 0x4a, 0x26, 0x21, 0x00, 0x10, 0x00, 0x00, 0x3a, 0xf2, 0x6c, 0x79, 0x00, 0x04, 0x00, ]; let packet = Packet::try_from(&buf); assert!(packet.is_err()); } #[test] fn test_decode_packet_with_unknown_extensions() { let buf = [ 0x21, 0x01, 0x41, 0xa7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0xdc, 0xab, 0x53, 0x3a, 0xf5, 0xff, 0x04, 0x00, 0x00, 0x00, 0x00, // Imaginary extension 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, ]; match Packet::try_from(&buf) { Ok(packet) => { assert_eq!(packet.get_version(), 1); assert_eq!(packet.get_extension_type(), ExtensionType::SelectiveAck); assert_eq!(packet.get_type(), State); assert_eq!(packet.connection_id(), 16807); assert_eq!(packet.timestamp(), Timestamp(0)); assert_eq!(packet.timestamp_difference(), Delay(0)); assert_eq!(packet.wnd_size(), 1500); assert_eq!(packet.seq_nr(), 43859); assert_eq!(packet.ack_nr(), 15093); assert!(packet.payload().is_empty()); // The invalid extension is discarded let extensions: Vec> = packet.extensions().collect(); assert_eq!(extensions.len(), 2); assert_eq!(extensions[0].ty, ExtensionType::SelectiveAck); assert_eq!(extensions[0].data, &[0, 0, 0, 0]); assert_eq!(extensions[0].len(), extensions[0].data.len()); assert_eq!(extensions[0].len(), 4); } Err(ref e) => panic!("{}", e), } } #[test] fn test_packet_set_type() { let mut packet = Packet::new(); packet.set_type(PacketType::Syn); assert_eq!(packet.get_type(), PacketType::Syn); packet.set_type(PacketType::State); assert_eq!(packet.get_type(), PacketType::State); packet.set_type(PacketType::Fin); assert_eq!(packet.get_type(), PacketType::Fin); packet.set_type(PacketType::Reset); assert_eq!(packet.get_type(), PacketType::Reset); packet.set_type(PacketType::Data); assert_eq!(packet.get_type(), PacketType::Data); } #[test] fn test_packet_set_selective_acknowledgment() { let mut packet = Packet::new(); packet.set_sack(vec![1, 2, 3, 4]); { let extensions: Vec> = packet.extensions().collect(); assert_eq!(extensions.len(), 1); assert_eq!(extensions[0].ty, ExtensionType::SelectiveAck); assert_eq!(extensions[0].data, &[1, 2, 3, 4]); assert_eq!(extensions[0].len(), extensions[0].data.len()); assert_eq!(extensions[0].len(), 4); } // Add a second sack packet.set_sack(vec![5, 6, 7, 8, 9, 10, 11, 12]); let extensions: Vec> = packet.extensions().collect(); assert_eq!(extensions.len(), 2); assert_eq!(extensions[0].ty, ExtensionType::SelectiveAck); assert_eq!(extensions[0].data, &[1, 2, 3, 4]); assert_eq!(extensions[0].len(), extensions[0].data.len()); assert_eq!(extensions[0].len(), 4); assert_eq!(extensions[1].ty, ExtensionType::SelectiveAck); assert_eq!(extensions[1].data, &[5, 6, 7, 8, 9, 10, 11, 12]); assert_eq!(extensions[1].len(), extensions[1].data.len()); assert_eq!(extensions[1].len(), 8); } #[test] fn test_packet_encode() { let payload = b"Hello\n".to_vec(); let timestamp = Timestamp(15270793); let timestamp_diff = Delay(1707040186); let (connection_id, seq_nr, ack_nr): (u16, u16, u16) = (16808, 15090, 17096); let window_size: u32 = 1048576; let mut packet = Packet::with_payload(&payload[..]); packet.set_type(Data); packet.set_timestamp(timestamp); packet.set_timestamp_difference(timestamp_diff); packet.set_connection_id(connection_id); packet.set_seq_nr(seq_nr); packet.set_ack_nr(ack_nr); packet.set_wnd_size(window_size); let buf = [ 0x01, 0x00, 0x41, 0xa8, 0x00, 0xe9, 0x03, 0x89, 0x65, 0xbf, 0x5d, 0xba, 0x00, 0x10, 0x00, 0x00, 0x3a, 0xf2, 0x42, 0xc8, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x0a, ]; assert_eq!(packet.len(), buf.len()); assert_eq!(packet.len(), HEADER_SIZE + payload.len()); assert_eq!(&packet.payload(), &payload.as_slice()); assert_eq!(packet.get_version(), 1); assert_eq!(packet.get_extension_type(), ExtensionType::None); assert_eq!(packet.get_type(), Data); assert_eq!(packet.connection_id(), connection_id); assert_eq!(packet.seq_nr(), seq_nr); assert_eq!(packet.ack_nr(), ack_nr); assert_eq!(packet.wnd_size(), window_size); assert_eq!(packet.timestamp(), timestamp); assert_eq!(packet.timestamp_difference(), timestamp_diff); assert_eq!(packet.as_ref(), buf); } #[test] fn test_packet_encode_with_payload() { let payload = b"Hello\n".to_vec(); let timestamp = Timestamp(15270793); let timestamp_diff = Delay(1707040186); let (connection_id, seq_nr, ack_nr): (u16, u16, u16) = (16808, 15090, 17096); let window_size: u32 = 1048576; let mut packet = Packet::with_payload(&payload[..]); packet.set_timestamp(timestamp); packet.set_timestamp_difference(timestamp_diff); packet.set_connection_id(connection_id); packet.set_seq_nr(seq_nr); packet.set_ack_nr(ack_nr); packet.set_wnd_size(window_size); let buf = [ 0x01, 0x00, 0x41, 0xa8, 0x00, 0xe9, 0x03, 0x89, 0x65, 0xbf, 0x5d, 0xba, 0x00, 0x10, 0x00, 0x00, 0x3a, 0xf2, 0x42, 0xc8, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x0a, ]; assert_eq!(packet.len(), buf.len()); assert_eq!(packet.len(), HEADER_SIZE + payload.len()); assert_eq!(&packet.payload(), &payload.as_slice()); assert_eq!(packet.get_version(), 1); assert_eq!(packet.get_type(), Data); assert_eq!(packet.get_extension_type(), ExtensionType::None); assert_eq!(packet.connection_id(), connection_id); assert_eq!(packet.seq_nr(), seq_nr); assert_eq!(packet.ack_nr(), ack_nr); assert_eq!(packet.wnd_size(), window_size); assert_eq!(packet.timestamp(), timestamp); assert_eq!(packet.timestamp_difference(), timestamp_diff); assert_eq!(packet.as_ref(), buf); } #[test] fn test_reversible() { let buf = [ 0x01, 0x00, 0x41, 0xa8, 0x00, 0xe9, 0x03, 0x89, 0x65, 0xbf, 0x5d, 0xba, 0x00, 0x10, 0x00, 0x00, 0x3a, 0xf2, 0x42, 0xc8, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x0a, ]; assert_eq!(&Packet::try_from(&buf).unwrap().as_ref(), &buf); } #[test] fn test_decode_evil_sequence() { let buf = [ 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ]; let packet = Packet::try_from(&buf); assert!(packet.is_err()); } #[test] fn test_decode_empty_packet() { let packet = Packet::try_from(&[]); assert!(packet.is_err()); } // Use quickcheck to simulate a malicious attacker sending malformed packets #[test] fn quicktest() { fn run(x: Vec) -> TestResult { let packet = Packet::try_from(&x); if PacketHeader::try_from(&x) .and(check_extensions(&x)) .is_err() { TestResult::from_bool(packet.is_err()) } else if let Ok(packet) = packet { TestResult::from_bool(&packet.as_ref() == &x.as_slice()) } else { TestResult::from_bool(false) } } QuickCheck::new() .tests(10000) .quickcheck(run as fn(Vec) -> TestResult) } #[test] fn extension_iterator() { let buf = [ 0x21, 0x00, 0x41, 0xa8, 0x99, 0x2f, 0xd0, 0x2a, 0x9f, 0x4a, 0x26, 0x21, 0x00, 0x10, 0x00, 0x00, 0x3a, 0xf2, 0x6c, 0x79, ]; let packet = Packet::try_from(&buf).unwrap(); assert_eq!(packet.extensions().count(), 0); let buf = [ 0x21, 0x01, 0x41, 0xa7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0xdc, 0xab, 0x53, 0x3a, 0xf5, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, ]; let packet = Packet::try_from(&buf).unwrap(); let extensions: Vec> = packet.extensions().collect(); assert_eq!(extensions.len(), 1); assert_eq!(extensions[0].ty, ExtensionType::SelectiveAck); assert_eq!(extensions[0].data, &[0, 0, 0, 0]); assert_eq!(extensions[0].len(), extensions[0].data.len()); assert_eq!(extensions[0].len(), 4); let buf = [ 0x21, 0x01, 0x41, 0xa7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0xdc, 0xab, 0x53, 0x3a, 0xf5, 0xff, 0x04, 0x01, 0x02, 0x03, 0x04, // Imaginary extension 0x00, 0x04, 0x05, 0x06, 0x07, 0x08, ]; let packet = Packet::try_from(&buf).unwrap(); let extensions: Vec> = packet.extensions().collect(); assert_eq!(extensions.len(), 2); assert_eq!(extensions[0].ty, ExtensionType::SelectiveAck); assert_eq!(extensions[0].data, &[1, 2, 3, 4]); assert_eq!(extensions[0].len(), extensions[0].data.len()); assert_eq!(extensions[0].len(), 4); assert_eq!(extensions[1].ty, ExtensionType::Unknown(0xff)); assert_eq!(extensions[1].data, &[5, 6, 7, 8]); assert_eq!(extensions[1].len(), extensions[1].data.len()); assert_eq!(extensions[1].len(), 4); } } #[cfg(all(feature = "unstable", test))] mod bench { extern crate test; use self::test::Bencher; use packet::{Packet, TryFrom}; #[bench] fn bench_decode(b: &mut Bencher) { let buf = [ 0x21, 0x00, 0x41, 0xa8, 0x99, 0x2f, 0xd0, 0x2a, 0x9f, 0x4a, 0x26, 0x21, 0x00, 0x10, 0x00, 0x00, 0x3a, 0xf2, 0x6c, 0x79, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, ]; b.iter(|| { let _ = test::black_box(Packet::try_from(&buf)); }); } #[bench] fn bench_encode(b: &mut Bencher) { let packet = Packet::with_payload(&[1, 2, 3, 4, 5, 6]); b.iter(|| { let _ = test::black_box(packet.as_ref()); }); } #[bench] fn bench_extract_payload(b: &mut Bencher) { let buf = [ 0x21, 0x01, 0x41, 0xa7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0xdc, 0xab, 0x53, 0x3a, 0xf5, 0xff, 0x04, 0x01, 0x02, 0x03, 0x04, // First extension 0x00, 0x04, 0x05, 0x06, 0x07, 0x08, // Second extension, followed by data 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ]; let packet = Packet::try_from(&buf).unwrap(); b.iter(|| { let _ = test::black_box(packet.payload()); }); } #[bench] fn bench_extract_extensions(b: &mut Bencher) { let buf = [ 0x21, 0x01, 0x41, 0xa7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0xdc, 0xab, 0x53, 0x3a, 0xf5, 0xff, 0x04, 0x01, 0x02, 0x03, 0x04, // First extension 0x00, 0x04, 0x05, 0x06, 0x07, 0x08, // Second extension, followed by data 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ]; let packet = Packet::try_from(&buf).unwrap(); b.iter(|| { let _ = test::black_box(packet.extensions().count()); }); } } ================================================ FILE: src/socket.rs ================================================ use crate::error::SocketError; use crate::packet::*; use crate::time::*; use crate::util::*; use log::debug; use std::cmp::{max, min}; use std::collections::VecDeque; use std::io::{ErrorKind, Result}; use std::net::{SocketAddr, ToSocketAddrs, UdpSocket}; use std::time::{Duration, Instant}; // For simplicity's sake, let us assume no packet will ever exceed the // Ethernet maximum transfer unit of 1500 bytes. const BUF_SIZE: usize = 1500; const GAIN: f64 = 1.0; const ALLOWED_INCREASE: u32 = 1; const TARGET: f64 = 100_000.0; // 100 milliseconds const MSS: u32 = 1400; const MIN_CWND: u32 = 2; const INIT_CWND: u32 = 2; const INITIAL_CONGESTION_TIMEOUT: u64 = 1000; // one second const MIN_CONGESTION_TIMEOUT: u64 = 500; // 500 ms const MAX_CONGESTION_TIMEOUT: u64 = 60_000; // one minute const BASE_HISTORY: usize = 10; // base delays history size const MAX_SYN_RETRIES: u32 = 5; // maximum connection retries const MAX_RETRANSMISSION_RETRIES: u32 = 5; // maximum retransmission retries const WINDOW_SIZE: u32 = 1024 * 1024; // local receive window size // Maximum time (in microseconds) to wait for incoming packets when the send window is full const PRE_SEND_TIMEOUT: u32 = 500_000; // Maximum age of base delay sample (60 seconds) const MAX_BASE_DELAY_AGE: Delay = Delay(60_000_000); #[derive(PartialEq, Eq, Debug, Copy, Clone)] enum SocketState { New, Connected, SynSent, FinSent, ResetReceived, Closed, } struct DelayDifferenceSample { received_at: Timestamp, difference: Delay, } /// Returns the first valid address in a `ToSocketAddrs` iterator. fn take_address(addr: A) -> Result { addr.to_socket_addrs() .and_then(|mut it| it.next().ok_or_else(|| SocketError::InvalidAddress.into())) } /// A structure that represents a uTP (Micro Transport Protocol) connection between a local socket /// and a remote socket. /// /// The socket will be closed when the value is dropped (either explicitly or when it goes out of /// scope). /// /// The default maximum retransmission retries is 5, which translates to about 16 seconds. It can be /// changed by assigning the desired maximum retransmission retries to a socket's /// `max_retransmission_retries` field. Notice that the initial congestion timeout is 500 ms and /// doubles with each timeout. /// /// # Examples /// /// ```no_run /// use utp::UtpSocket; /// /// let mut socket = UtpSocket::bind("127.0.0.1:1234").expect("Error binding socket"); /// /// let mut buf = [0; 1000]; /// let (amt, _src) = socket.recv_from(&mut buf).expect("Error receiving"); /// /// let mut buf = &mut buf[..amt]; /// buf.reverse(); /// let _ = socket.send_to(buf).expect("Error sending"); /// /// // Close the socket. You can either call `close` on the socket, /// // explicitly drop it or just let it go out of scope. /// socket.close(); /// ``` pub struct UtpSocket { /// The wrapped UDP socket socket: UdpSocket, /// Remote peer connected_to: SocketAddr, /// Sender connection identifier sender_connection_id: u16, /// Receiver connection identifier receiver_connection_id: u16, /// Sequence number for the next packet seq_nr: u16, /// Sequence number of the latest acknowledged packet sent by the remote peer ack_nr: u16, /// Socket state state: SocketState, /// Received but not acknowledged packets incoming_buffer: Vec, /// Sent but not yet acknowledged packets send_window: Vec, /// Packets not yet sent unsent_queue: VecDeque, /// How many ACKs did the socket receive for packet with sequence number equal to `ack_nr` duplicate_ack_count: u32, /// Sequence number of the latest packet the remote peer acknowledged last_acked: u16, /// Timestamp of the latest packet the remote peer acknowledged last_acked_timestamp: Timestamp, /// Sequence number of the last packet removed from the incoming buffer last_dropped: u16, /// Round-trip time to remote peer rtt: i32, /// Variance of the round-trip time to the remote peer rtt_variance: i32, /// Data from the latest packet not yet returned in `recv_from` pending_data: Vec, /// Bytes in flight curr_window: u32, /// Window size of the remote peer remote_wnd_size: u32, /// Rolling window of packet delay to remote peer base_delays: VecDeque, /// Rolling window of the difference between sending a packet and receiving its acknowledgement current_delays: Vec, /// Difference between timestamp of the latest packet received and time of reception their_delay: Delay, /// Start of the current minute for sampling purposes last_rollover: Timestamp, /// Current congestion timeout in milliseconds congestion_timeout: u64, /// Congestion window in bytes cwnd: u32, /// Maximum retransmission retries pub max_retransmission_retries: u32, } impl UtpSocket { /// Creates a new UTP socket from the given UDP socket and the remote peer's address. /// /// The connection identifier of the resulting socket is randomly generated. fn from_raw_parts(s: UdpSocket, src: SocketAddr) -> UtpSocket { let (receiver_id, sender_id) = generate_sequential_identifiers(); UtpSocket { socket: s, connected_to: src, receiver_connection_id: receiver_id, sender_connection_id: sender_id, seq_nr: 1, ack_nr: 0, state: SocketState::New, incoming_buffer: Vec::new(), send_window: Vec::new(), unsent_queue: VecDeque::new(), duplicate_ack_count: 0, last_acked: 0, last_acked_timestamp: Timestamp::default(), last_dropped: 0, rtt: 0, rtt_variance: 0, pending_data: Vec::new(), curr_window: 0, remote_wnd_size: 0, current_delays: Vec::new(), base_delays: VecDeque::with_capacity(BASE_HISTORY), their_delay: Delay::default(), last_rollover: Timestamp::default(), congestion_timeout: INITIAL_CONGESTION_TIMEOUT, cwnd: INIT_CWND * MSS, max_retransmission_retries: MAX_RETRANSMISSION_RETRIES, } } /// Creates a new UTP socket from the given address. /// /// The address type can be any implementer of the `ToSocketAddr` trait. See its documentation /// for concrete examples. /// /// If more than one valid address is specified, only the first will be used. pub fn bind(addr: A) -> Result { take_address(addr).and_then(|a| UdpSocket::bind(a).map(|s| UtpSocket::from_raw_parts(s, a))) } /// Returns the socket address that this socket was created from. pub fn local_addr(&self) -> Result { self.socket.local_addr() } /// Returns the socket address of the remote peer of this UTP connection. pub fn peer_addr(&self) -> Result { if self.state == SocketState::Connected || self.state == SocketState::FinSent { Ok(self.connected_to) } else { Err(SocketError::NotConnected.into()) } } /// Opens a connection to a remote host by hostname or IP address. /// /// The address type can be any implementer of the `ToSocketAddr` trait. See its documentation /// for concrete examples. /// /// If more than one valid address is specified, only the first will be used. pub fn connect(other: A) -> Result { let addr = take_address(other)?; let my_addr = match addr { SocketAddr::V4(_) => "0.0.0.0:0", SocketAddr::V6(_) => "[::]:0", }; let mut socket = UtpSocket::bind(my_addr)?; socket.connected_to = addr; let mut packet = Packet::new(); packet.set_type(PacketType::Syn); packet.set_connection_id(socket.receiver_connection_id); packet.set_seq_nr(socket.seq_nr); let mut len = 0; let mut buf = [0; BUF_SIZE]; let mut syn_timeout = socket.congestion_timeout; for _ in 0..MAX_SYN_RETRIES { packet.set_timestamp(now_microseconds()); // Send packet debug!("Connecting to {}", socket.connected_to); socket .socket .send_to(packet.as_ref(), socket.connected_to)?; socket.state = SocketState::SynSent; debug!("sent {:?}", packet); // Validate response socket .socket .set_read_timeout(Some(Duration::from_millis(syn_timeout))) .expect("Error setting read timeout"); match socket.socket.recv_from(&mut buf) { Ok((read, src)) => { socket.connected_to = src; len = read; break; } Err(ref e) if (e.kind() == ErrorKind::WouldBlock || e.kind() == ErrorKind::TimedOut) => { debug!("Timed out, retrying"); syn_timeout *= 2; continue; } Err(e) => return Err(e), }; } let addr = socket.connected_to; let packet = Packet::try_from(&buf[..len])?; debug!("received {:?}", packet); socket.handle_packet(&packet, addr)?; debug!("connected to: {}", socket.connected_to); Ok(socket) } /// Gracefully closes connection to peer. /// /// This method allows both peers to receive all packets still in /// flight. pub fn close(&mut self) -> Result<()> { // Nothing to do if the socket's already closed or not connected if self.state == SocketState::Closed || self.state == SocketState::New || self.state == SocketState::SynSent { return Ok(()); } // Flush unsent and unacknowledged packets self.flush()?; let mut packet = Packet::new(); packet.set_connection_id(self.sender_connection_id); packet.set_seq_nr(self.seq_nr); packet.set_ack_nr(self.ack_nr); packet.set_timestamp(now_microseconds()); packet.set_type(PacketType::Fin); // Send FIN self.socket.send_to(packet.as_ref(), self.connected_to)?; debug!("sent {:?}", packet); self.state = SocketState::FinSent; // Receive JAKE let mut buf = [0; BUF_SIZE]; while self.state != SocketState::Closed { self.recv(&mut buf)?; } Ok(()) } /// Receives data from socket. /// /// On success, returns the number of bytes read and the sender's address. /// Returns 0 bytes read after receiving a FIN packet when the remaining /// in-flight packets are consumed. pub fn recv_from(&mut self, buf: &mut [u8]) -> Result<(usize, SocketAddr)> { let read = self.flush_incoming_buffer(buf); if read > 0 { return Ok((read, self.connected_to)); } // If the socket received a reset packet and all data has been flushed, then it can't // receive anything else if self.state == SocketState::ResetReceived { return Err(SocketError::ConnectionReset.into()); } loop { // A closed socket with no pending data can only "read" 0 new bytes. if self.state == SocketState::Closed { return Ok((0, self.connected_to)); } match self.recv(buf) { Ok((0, _src)) => continue, Ok(x) => return Ok(x), Err(e) => return Err(e), } } } fn recv(&mut self, buf: &mut [u8]) -> Result<(usize, SocketAddr)> { let mut b = [0; BUF_SIZE + HEADER_SIZE]; let start = Instant::now(); let (read, src); let mut retries = 0; // Try to receive a packet and handle timeouts loop { // Abort loop if the current try exceeds the maximum number of retransmission retries. if retries >= self.max_retransmission_retries { self.state = SocketState::Closed; return Err(SocketError::ConnectionTimedOut.into()); } let timeout = if self.state != SocketState::New { debug!("setting read timeout of {} ms", self.congestion_timeout); Some(Duration::from_millis(self.congestion_timeout)) } else { None }; self.socket .set_read_timeout(timeout) .expect("Error setting read timeout"); match self.socket.recv_from(&mut b) { Ok((r, s)) => { read = r; src = s; break; } Err(ref e) if (e.kind() == ErrorKind::WouldBlock || e.kind() == ErrorKind::TimedOut) => { debug!("recv_from timed out"); self.handle_receive_timeout()?; } Err(e) => return Err(e), }; let elapsed = start.elapsed(); let elapsed_ms = elapsed.as_secs() * 1000 + elapsed.subsec_millis() as u64; debug!("{} ms elapsed", elapsed_ms); retries += 1; } // Decode received data into a packet let packet = match Packet::try_from(&b[..read]) { Ok(packet) => packet, Err(e) => { debug!("{}", e); debug!("Ignoring invalid packet"); return Ok((0, self.connected_to)); } }; debug!("received {:?}", packet); // Process packet, including sending a reply if necessary if let Some(mut pkt) = self.handle_packet(&packet, src)? { pkt.set_wnd_size(WINDOW_SIZE); self.socket.send_to(pkt.as_ref(), src)?; debug!("sent {:?}", pkt); } // Insert data packet into the incoming buffer if it isn't a duplicate of a previously // discarded packet if packet.get_type() == PacketType::Data && packet.seq_nr().wrapping_sub(self.last_dropped) > 0 { self.insert_into_buffer(packet); } // Flush incoming buffer if possible let read = self.flush_incoming_buffer(buf); Ok((read, src)) } fn handle_receive_timeout(&mut self) -> Result<()> { self.congestion_timeout *= 2; self.cwnd = MSS; // There are three possible cases here: // // - If the socket is sending and waiting for acknowledgements (the send window is // not empty), resend the first unacknowledged packet; // // - If the socket is not sending and it hasn't sent a FIN yet, then it's waiting // for incoming packets: send a fast resend request; // // - If the socket sent a FIN previously, resend it. debug!( "self.send_window: {:?}", self.send_window .iter() .map(Packet::seq_nr) .collect::>() ); if self.send_window.is_empty() { // The socket is trying to close, all sent packets were acknowledged, and it has // already sent a FIN: resend it. if self.state == SocketState::FinSent { let mut packet = Packet::new(); packet.set_connection_id(self.sender_connection_id); packet.set_seq_nr(self.seq_nr); packet.set_ack_nr(self.ack_nr); packet.set_timestamp(now_microseconds()); packet.set_type(PacketType::Fin); // Send FIN self.socket.send_to(packet.as_ref(), self.connected_to)?; debug!("resent FIN: {:?}", packet); } else if self.state != SocketState::New { // The socket is waiting for incoming packets but the remote peer is silent: // send a fast resend request. debug!("sending fast resend request"); self.send_fast_resend_request(); } } else { // The socket is sending data packets but there is no reply from the remote // peer: resend the first unacknowledged packet with the current timestamp. let packet = &mut self.send_window[0]; packet.set_timestamp(now_microseconds()); self.socket.send_to(packet.as_ref(), self.connected_to)?; debug!("resent {:?}", packet); } Ok(()) } fn prepare_reply(&self, original: &Packet, t: PacketType) -> Packet { let mut resp = Packet::new(); resp.set_type(t); let self_t_micro = now_microseconds(); let other_t_micro = original.timestamp(); let time_difference: Delay = abs_diff(self_t_micro, other_t_micro); resp.set_timestamp(self_t_micro); resp.set_timestamp_difference(time_difference); resp.set_connection_id(self.sender_connection_id); resp.set_seq_nr(self.seq_nr); resp.set_ack_nr(self.ack_nr); resp } /// Removes a packet in the incoming buffer and updates the current acknowledgement number. fn advance_incoming_buffer(&mut self) -> Option { if !self.incoming_buffer.is_empty() { let packet = self.incoming_buffer.remove(0); debug!("Removed packet from incoming buffer: {:?}", packet); self.ack_nr = packet.seq_nr(); self.last_dropped = self.ack_nr; Some(packet) } else { None } } /// Discards sequential, ordered packets in incoming buffer, starting from /// the most recently acknowledged to the most recent, as long as there are /// no missing packets. The discarded packets' payload is written to the /// slice `buf`, starting in position `start`. /// Returns the last written index. fn flush_incoming_buffer(&mut self, buf: &mut [u8]) -> usize { fn unsafe_copy(src: &[u8], dst: &mut [u8]) -> usize { let max_len = min(src.len(), dst.len()); unsafe { use std::ptr::copy; copy(src.as_ptr(), dst.as_mut_ptr(), max_len); } max_len } // Return pending data from a partially read packet if !self.pending_data.is_empty() { let flushed = unsafe_copy(&self.pending_data[..], buf); if flushed == self.pending_data.len() { self.pending_data.clear(); self.advance_incoming_buffer(); } else { self.pending_data = self.pending_data[flushed..].to_vec(); } return flushed; } if !self.incoming_buffer.is_empty() && (self.ack_nr == self.incoming_buffer[0].seq_nr() || self.ack_nr + 1 == self.incoming_buffer[0].seq_nr()) { let flushed = unsafe_copy(&self.incoming_buffer[0].payload(), buf); if flushed == self.incoming_buffer[0].payload().len() { self.advance_incoming_buffer(); } else { self.pending_data = self.incoming_buffer[0].payload()[flushed..].to_vec(); } return flushed; } 0 } /// Sends data on the socket to the remote peer. On success, returns the number of bytes /// written. // // # Implementation details // // This method inserts packets into the send buffer and keeps trying to // advance the send window until an ACK corresponding to the last packet is // received. // // Note that the buffer passed to `send_to` might exceed the maximum packet // size, which will result in the data being split over several packets. pub fn send_to(&mut self, buf: &[u8]) -> Result { if self.state == SocketState::Closed { return Err(SocketError::ConnectionClosed.into()); } let total_length = buf.len(); for chunk in buf.chunks(MSS as usize - HEADER_SIZE) { let mut packet = Packet::with_payload(chunk); packet.set_seq_nr(self.seq_nr); packet.set_ack_nr(self.ack_nr); packet.set_connection_id(self.sender_connection_id); self.unsent_queue.push_back(packet); // Intentionally wrap around sequence number self.seq_nr = self.seq_nr.wrapping_add(1); } // Send every packet in the queue self.send()?; Ok(total_length) } /// Consumes acknowledgements for every pending packet. pub fn flush(&mut self) -> Result<()> { let mut buf = [0u8; BUF_SIZE]; while !self.send_window.is_empty() { debug!("packets in send window: {}", self.send_window.len()); self.recv(&mut buf)?; } Ok(()) } /// Sends every packet in the unsent packet queue. fn send(&mut self) -> Result<()> { while let Some(mut packet) = self.unsent_queue.pop_front() { self.send_packet(&mut packet)?; self.curr_window += packet.len() as u32; self.send_window.push(packet); } Ok(()) } /// Send one packet. #[inline] fn send_packet(&mut self, packet: &mut Packet) -> Result<()> { debug!("current window: {}", self.send_window.len()); let max_inflight = min(self.cwnd, self.remote_wnd_size); let max_inflight = max(MIN_CWND * MSS, max_inflight); let now = now_microseconds(); // Wait until enough in-flight packets are acknowledged for rate control purposes, but don't // wait more than 500 ms (PRE_SEND_TIMEOUT) before sending the packet. while self.curr_window >= max_inflight && now_microseconds() - now < PRE_SEND_TIMEOUT.into() { debug!("self.curr_window: {}", self.curr_window); debug!("max_inflight: {}", max_inflight); debug!("self.duplicate_ack_count: {}", self.duplicate_ack_count); debug!("now_microseconds() - now = {}", now_microseconds() - now); let mut buf = [0; BUF_SIZE]; self.recv(&mut buf)?; } debug!( "out: now_microseconds() - now = {}", now_microseconds() - now ); // Check if it still makes sense to send packet, as we might be trying to resend a lost // packet acknowledged in the receive loop above. // If there were no wrapping around of sequence numbers, we'd simply check if the packet's // sequence number is greater than `last_acked`. let distance_a = packet.seq_nr().wrapping_sub(self.last_acked); let distance_b = self.last_acked.wrapping_sub(packet.seq_nr()); if distance_a > distance_b { debug!("Packet already acknowledged, skipping..."); return Ok(()); } packet.set_timestamp(now_microseconds()); packet.set_timestamp_difference(self.their_delay); self.socket.send_to(packet.as_ref(), self.connected_to)?; debug!("sent {:?}", packet); Ok(()) } // Insert a new sample in the base delay list. // // The base delay list contains at most `BASE_HISTORY` samples, each sample is the minimum // measured over a period of a minute (MAX_BASE_DELAY_AGE). fn update_base_delay(&mut self, base_delay: Delay, now: Timestamp) { if self.base_delays.is_empty() || now - self.last_rollover > MAX_BASE_DELAY_AGE { // Update last rollover self.last_rollover = now; // Drop the oldest sample, if need be if self.base_delays.len() == BASE_HISTORY { self.base_delays.pop_front(); } // Insert new sample self.base_delays.push_back(base_delay); } else { // Replace sample for the current minute if the delay is lower let last_idx = self.base_delays.len() - 1; if base_delay < self.base_delays[last_idx] { self.base_delays[last_idx] = base_delay; } } } /// Inserts a new sample in the current delay list after removing samples older than one RTT, as /// specified in RFC6817. fn update_current_delay(&mut self, v: Delay, now: Timestamp) { // Remove samples more than one RTT old let rtt = (self.rtt as i64 * 100).into(); while !self.current_delays.is_empty() && now - self.current_delays[0].received_at > rtt { self.current_delays.remove(0); } // Insert new measurement self.current_delays.push(DelayDifferenceSample { received_at: now, difference: v, }); } fn update_congestion_timeout(&mut self, current_delay: i32) { let delta = self.rtt - current_delay; self.rtt_variance += (delta.abs() - self.rtt_variance) / 4; self.rtt += (current_delay - self.rtt) / 8; self.congestion_timeout = max( (self.rtt + self.rtt_variance * 4) as u64, MIN_CONGESTION_TIMEOUT, ); self.congestion_timeout = min(self.congestion_timeout, MAX_CONGESTION_TIMEOUT); debug!("current_delay: {}", current_delay); debug!("delta: {}", delta); debug!("self.rtt_variance: {}", self.rtt_variance); debug!("self.rtt: {}", self.rtt); debug!("self.congestion_timeout: {}", self.congestion_timeout); } /// Calculates the filtered current delay in the current window. /// /// The current delay is calculated through application of the exponential /// weighted moving average filter with smoothing factor 0.333 over the /// current delays in the current window. fn filtered_current_delay(&self) -> Delay { let input = self.current_delays.iter().map(|delay| &delay.difference); (ewma(input, 0.333) as i64).into() } /// Calculates the lowest base delay in the current window. fn min_base_delay(&self) -> Delay { self.base_delays.iter().min().cloned().unwrap_or_default() } /// Builds the selective acknowledgement extension data for usage in packets. fn build_selective_ack(&self) -> Vec { let stashed = self .incoming_buffer .iter() .filter(|pkt| pkt.seq_nr() > self.ack_nr + 1) .map(|pkt| (pkt.seq_nr() - self.ack_nr - 2) as usize) .map(|diff| (diff / 8, diff % 8)); let mut sack = Vec::new(); for (byte, bit) in stashed { // Make sure the amount of elements in the SACK vector is a // multiple of 4 and enough to represent the lost packets while byte >= sack.len() || sack.len() % 4 != 0 { sack.push(0u8); } sack[byte] |= 1 << bit; } sack } /// Sends a fast resend request to the remote peer. /// /// A fast resend request consists of sending three State packets (acknowledging the last /// received packet) in quick succession. fn send_fast_resend_request(&self) { for _ in 0..3 { let mut packet = Packet::new(); packet.set_type(PacketType::State); let self_t_micro = now_microseconds(); packet.set_timestamp(self_t_micro); packet.set_timestamp_difference(self.their_delay); packet.set_connection_id(self.sender_connection_id); packet.set_seq_nr(self.seq_nr); packet.set_ack_nr(self.ack_nr); let _ = self.socket.send_to(packet.as_ref(), self.connected_to); } } fn resend_lost_packet(&mut self, lost_packet_nr: u16) { debug!("---> resend_lost_packet({}) <---", lost_packet_nr); match self .send_window .iter() .position(|pkt| pkt.seq_nr() == lost_packet_nr) { None => debug!("Packet {} not found", lost_packet_nr), Some(position) => { debug!("self.send_window.len(): {}", self.send_window.len()); debug!("position: {}", position); let mut packet = self.send_window[position].clone(); // FIXME: Unchecked result let _ = self.send_packet(&mut packet); // We intentionally don't increase `curr_window` because otherwise a packet's length // would be counted more than once } } debug!("---> END resend_lost_packet <---"); } /// Forgets sent packets that were acknowledged by the remote peer. fn advance_send_window(&mut self) { // The reason I'm not removing the first element in a loop while its sequence number is // smaller than `last_acked` is because of wrapping sequence numbers, which would create the // sequence [..., 65534, 65535, 0, 1, ...]. If `last_acked` is smaller than the first // packet's sequence number because of wraparound (for instance, 1), no packets would be // removed, as the condition `seq_nr < last_acked` would fail immediately. // // On the other hand, I can't keep removing the first packet in a loop until its sequence // number matches `last_acked` because it might never match, and in that case no packets // should be removed. if let Some(position) = self .send_window .iter() .position(|packet| packet.seq_nr() == self.last_acked) { for _ in 0..position + 1 { let packet = self.send_window.remove(0); self.curr_window -= packet.len() as u32; } } debug!("self.curr_window: {}", self.curr_window); } /// Handles an incoming packet, updating socket state accordingly. /// /// Returns the appropriate reply packet, if needed. fn handle_packet(&mut self, packet: &Packet, src: SocketAddr) -> Result> { debug!("({:?}, {:?})", self.state, packet.get_type()); // Acknowledge only if the packet strictly follows the previous one if packet.seq_nr().wrapping_sub(self.ack_nr) == 1 { self.ack_nr = packet.seq_nr(); } // Reset connection if connection id doesn't match and this isn't a SYN if packet.get_type() != PacketType::Syn && self.state != SocketState::SynSent && !(packet.connection_id() == self.sender_connection_id || packet.connection_id() == self.receiver_connection_id) { return Ok(Some(self.prepare_reply(packet, PacketType::Reset))); } // Update remote window size self.remote_wnd_size = packet.wnd_size(); debug!("self.remote_wnd_size: {}", self.remote_wnd_size); // Update remote peer's delay between them sending the packet and us receiving it let now = now_microseconds(); self.their_delay = abs_diff(now, packet.timestamp()); debug!("self.their_delay: {}", self.their_delay); match (self.state, packet.get_type()) { (SocketState::New, PacketType::Syn) => { self.connected_to = src; self.ack_nr = packet.seq_nr(); self.seq_nr = rand::random(); self.receiver_connection_id = packet.connection_id() + 1; self.sender_connection_id = packet.connection_id(); self.state = SocketState::Connected; self.last_dropped = self.ack_nr; Ok(Some(self.prepare_reply(packet, PacketType::State))) } (_, PacketType::Syn) => Ok(Some(self.prepare_reply(packet, PacketType::Reset))), (SocketState::SynSent, PacketType::State) => { self.connected_to = src; self.ack_nr = packet.seq_nr(); self.seq_nr += 1; self.state = SocketState::Connected; self.last_acked = packet.ack_nr(); self.last_acked_timestamp = now_microseconds(); Ok(None) } (SocketState::SynSent, _) => Err(SocketError::InvalidReply.into()), (SocketState::Connected, PacketType::Data) | (SocketState::FinSent, PacketType::Data) => Ok(self.handle_data_packet(packet)), (SocketState::Connected, PacketType::State) => { self.handle_state_packet(packet); Ok(None) } (SocketState::Connected, PacketType::Fin) | (SocketState::FinSent, PacketType::Fin) => { if packet.ack_nr() < self.seq_nr { debug!("FIN received but there are missing acknowledgements for sent packets"); } let mut reply = self.prepare_reply(packet, PacketType::State); if packet.seq_nr().wrapping_sub(self.ack_nr) > 1 { debug!( "current ack_nr ({}) is behind received packet seq_nr ({})", self.ack_nr, packet.seq_nr() ); // Set SACK extension payload if the packet is not in order let sack = self.build_selective_ack(); if !sack.is_empty() { reply.set_sack(sack); } } // Give up, the remote peer might not care about our missing packets self.state = SocketState::Closed; Ok(Some(reply)) } (SocketState::Closed, PacketType::Fin) => { Ok(Some(self.prepare_reply(packet, PacketType::State))) } (SocketState::FinSent, PacketType::State) => { if packet.ack_nr() == self.seq_nr { self.state = SocketState::Closed; } else { self.handle_state_packet(packet); } Ok(None) } (_, PacketType::Reset) => { self.state = SocketState::ResetReceived; Err(SocketError::ConnectionReset.into()) } (state, ty) => { let message = format!("Unimplemented handling for ({:?},{:?})", state, ty); debug!("{}", message); Err(SocketError::Other(message).into()) } } } fn handle_data_packet(&mut self, packet: &Packet) -> Option { // If a FIN was previously sent, reply with a FIN packet acknowledging the received packet. let packet_type = if self.state == SocketState::FinSent { PacketType::Fin } else { PacketType::State }; let mut reply = self.prepare_reply(packet, packet_type); if packet.seq_nr().wrapping_sub(self.ack_nr) > 1 { debug!( "current ack_nr ({}) is behind received packet seq_nr ({})", self.ack_nr, packet.seq_nr() ); // Set SACK extension payload if the packet is not in order let sack = self.build_selective_ack(); if !sack.is_empty() { reply.set_sack(sack); } } Some(reply) } fn queuing_delay(&self) -> Delay { let filtered_current_delay = self.filtered_current_delay(); let min_base_delay = self.min_base_delay(); let queuing_delay = filtered_current_delay - min_base_delay; debug!("filtered_current_delay: {}", filtered_current_delay); debug!("min_base_delay: {}", min_base_delay); debug!("queuing_delay: {}", queuing_delay); queuing_delay } /// Calculates the new congestion window size, increasing it or decreasing it. /// /// This is the core of uTP, the [LEDBAT][ledbat_rfc] congestion algorithm. It depends on /// estimating the queuing delay between the two peers, and adjusting the congestion window /// accordingly. /// /// `off_target` is a normalized value representing the difference between the current queuing /// delay and a fixed target delay (`TARGET`). `off_target` ranges between -1.0 and 1.0. A /// positive value makes the congestion window increase, while a negative value makes the /// congestion window decrease. /// /// `bytes_newly_acked` is the number of bytes acknowledged by an inbound `State` packet. It may /// be the size of the packet explicitly acknowledged by the inbound packet (i.e., with sequence /// number equal to the inbound packet's acknowledgement number), or every packet implicitly /// acknowledged (every packet with sequence number between the previous inbound `State` /// packet's acknowledgement number and the current inbound `State` packet's acknowledgement /// number). /// ///[ledbat_rfc]: https://tools.ietf.org/html/rfc6817 fn update_congestion_window(&mut self, off_target: f64, bytes_newly_acked: u32) { let flightsize = self.curr_window; let cwnd_increase = GAIN * off_target * bytes_newly_acked as f64 * MSS as f64; let cwnd_increase = cwnd_increase / self.cwnd as f64; debug!("cwnd_increase: {}", cwnd_increase); self.cwnd = (self.cwnd as f64 + cwnd_increase) as u32; let max_allowed_cwnd = flightsize + ALLOWED_INCREASE * MSS; self.cwnd = min(self.cwnd, max_allowed_cwnd); self.cwnd = max(self.cwnd, MIN_CWND * MSS); debug!("cwnd: {}", self.cwnd); debug!("max_allowed_cwnd: {}", max_allowed_cwnd); } fn handle_state_packet(&mut self, packet: &Packet) { if packet.ack_nr() == self.last_acked { self.duplicate_ack_count += 1; } else { self.last_acked = packet.ack_nr(); self.last_acked_timestamp = now_microseconds(); self.duplicate_ack_count = 1; } // Update congestion window size if let Some(index) = self .send_window .iter() .position(|p| packet.ack_nr() == p.seq_nr()) { // Calculate the sum of the size of every packet implicitly and explicitly acknowledged // by the inbound packet (i.e., every packet whose sequence number precedes the inbound // packet's acknowledgement number, plus the packet whose sequence number matches) let bytes_newly_acked = self .send_window .iter() .take(index + 1) .fold(0, |acc, p| acc + p.len()); // Update base and current delay let now = now_microseconds(); let our_delay = now - self.send_window[index].timestamp(); debug!("our_delay: {}", our_delay); self.update_base_delay(our_delay, now); self.update_current_delay(our_delay, now); let off_target: f64 = (TARGET - u32::from(self.queuing_delay()) as f64) / TARGET; debug!("off_target: {}", off_target); self.update_congestion_window(off_target, bytes_newly_acked as u32); // Update congestion timeout let rtt = u32::from(our_delay - self.queuing_delay()) / 1000; // in milliseconds self.update_congestion_timeout(rtt as i32); } let mut packet_loss_detected: bool = !self.send_window.is_empty() && self.duplicate_ack_count == 3; // Process extensions, if any for extension in packet.extensions() { if extension.get_type() == ExtensionType::SelectiveAck { // If three or more packets are acknowledged past the implicit missing one, // assume it was lost. if extension.iter().count_ones() >= 3 { self.resend_lost_packet(packet.ack_nr() + 1); packet_loss_detected = true; } if let Some(last_seq_nr) = self.send_window.last().map(Packet::seq_nr) { let lost_packets = extension .iter() .enumerate() .filter(|&(_, received)| !received) .map(|(idx, _)| packet.ack_nr() + 2 + idx as u16) .take_while(|&seq_nr| seq_nr < last_seq_nr); for seq_nr in lost_packets { debug!("SACK: packet {} lost", seq_nr); self.resend_lost_packet(seq_nr); packet_loss_detected = true; } } } else { debug!("Unknown extension {:?}, ignoring", extension.get_type()); } } // Three duplicate ACKs mean a fast resend request. Resend the first unacknowledged packet // if the incoming packet doesn't have a SACK extension. If it does, the lost packets were // already resent. if !self.send_window.is_empty() && self.duplicate_ack_count == 3 && !packet .extensions() .any(|ext| ext.get_type() == ExtensionType::SelectiveAck) { self.resend_lost_packet(packet.ack_nr() + 1); } // Packet lost, halve the congestion window if packet_loss_detected { debug!("packet loss detected, halving congestion window"); self.cwnd = max(self.cwnd / 2, MIN_CWND * MSS); debug!("cwnd: {}", self.cwnd); } // Success, advance send window self.advance_send_window(); } /// Inserts a packet into the socket's buffer. /// /// The packet is inserted in such a way that the packets in the buffer are sorted according to /// their sequence number in ascending order. This allows storing packets that were received out /// of order. /// /// Trying to insert a duplicate of a packet will silently fail. /// it's more recent (larger timestamp). fn insert_into_buffer(&mut self, packet: Packet) { // Immediately push to the end if the packet's sequence number comes after the last // packet's. if self .incoming_buffer .last() .map_or(false, |p| packet.seq_nr() > p.seq_nr()) { self.incoming_buffer.push(packet); } else { // Find index following the most recent packet before the one we wish to insert let i = self .incoming_buffer .iter() .filter(|p| p.seq_nr() < packet.seq_nr()) .count(); if self .incoming_buffer .get(i) .map_or(true, |p| p.seq_nr() != packet.seq_nr()) { self.incoming_buffer.insert(i, packet); } } } } impl Drop for UtpSocket { fn drop(&mut self) { let _ = self.close(); } } /// A structure representing a socket server. /// /// # Examples /// /// ```no_run /// use utp::{UtpListener, UtpSocket}; /// use std::thread; /// /// fn handle_client(socket: UtpSocket) { /// // ... /// } /// /// fn main() { /// // Create a listener /// let addr = "127.0.0.1:8080"; /// let listener = UtpListener::bind(addr).expect("Error binding socket"); /// /// for connection in listener.incoming() { /// // Spawn a new handler for each new connection /// if let Ok((socket, _src)) = connection { /// thread::spawn(move || handle_client(socket)); /// } /// } /// } /// ``` pub struct UtpListener { /// The public facing UDP socket socket: UdpSocket, } impl UtpListener { /// Creates a new `UtpListener` bound to a specific address. /// /// The resulting listener is ready for accepting connections. /// /// The address type can be any implementer of the `ToSocketAddr` trait. See its documentation /// for concrete examples. /// /// If more than one valid address is specified, only the first will be used. pub fn bind(addr: A) -> Result { UdpSocket::bind(addr).map(|s| UtpListener { socket: s }) } /// Accepts a new incoming connection from this listener. /// /// This function will block the caller until a new uTP connection is established. When /// established, the corresponding `UtpSocket` and the peer's remote address will be returned. /// /// Notice that the resulting `UtpSocket` is bound to a different local port than the public /// listening port (which `UtpListener` holds). This may confuse the remote peer! pub fn accept(&self) -> Result<(UtpSocket, SocketAddr)> { let mut buf = [0; BUF_SIZE]; self.socket.recv_from(&mut buf).and_then(|(nread, src)| { let packet = Packet::try_from(&buf[..nread])?; // Ignore non-SYN packets if packet.get_type() != PacketType::Syn { let message = format!("Expected SYN packet, got {:?} instead", packet.get_type()); return Err(SocketError::Other(message).into()); } // The address of the new socket will depend on the type of the listener. let inner_socket = self.socket.local_addr().and_then(|addr| match addr { SocketAddr::V4(_) => UdpSocket::bind("0.0.0.0:0"), SocketAddr::V6(_) => UdpSocket::bind("[::]:0"), }); let mut socket = inner_socket.map(|s| UtpSocket::from_raw_parts(s, src))?; // Establish connection with remote peer if let Ok(Some(reply)) = socket.handle_packet(&packet, src) { socket .socket .send_to(reply.as_ref(), src) .and(Ok((socket, src))) } else { Err(SocketError::Other("Reached unreachable statement".to_owned()).into()) } }) } /// Returns an iterator over the connections being received by this listener. /// /// The returned iterator will never return `None`. pub fn incoming(&self) -> Incoming<'_> { Incoming { listener: self } } /// Returns the local socket address of this listener. pub fn local_addr(&self) -> Result { self.socket.local_addr() } } pub struct Incoming<'a> { listener: &'a UtpListener, } impl<'a> Iterator for Incoming<'a> { type Item = Result<(UtpSocket, SocketAddr)>; fn next(&mut self) -> Option> { Some(self.listener.accept()) } } #[cfg(test)] mod test { use crate::packet::*; use crate::socket::{take_address, SocketState, UtpListener, UtpSocket, BUF_SIZE}; use crate::time::now_microseconds; use rand; use std::io::ErrorKind; use std::net::ToSocketAddrs; use std::thread; macro_rules! iotry { ($e:expr) => { match $e { Ok(e) => e, Err(e) => panic!("{:?}", e), } }; } fn next_test_port() -> u16 { use std::sync::atomic::{AtomicUsize, Ordering}; static NEXT_OFFSET: AtomicUsize = AtomicUsize::new(0); const BASE_PORT: u16 = 9600; BASE_PORT + NEXT_OFFSET.fetch_add(1, Ordering::Relaxed) as u16 } fn next_test_ip4<'a>() -> (&'a str, u16) { ("127.0.0.1", next_test_port()) } fn next_test_ip6<'a>() -> (&'a str, u16) { ("::1", next_test_port()) } #[test] fn test_socket_ipv4() { let server_addr = next_test_ip4(); let mut server = iotry!(UtpSocket::bind(server_addr)); assert_eq!(server.state, SocketState::New); let child = thread::spawn(move || { let mut client = iotry!(UtpSocket::connect(server_addr)); assert_eq!(client.state, SocketState::Connected); // Check proper difference in client's send connection id and receive connection id assert_eq!( client.sender_connection_id, client.receiver_connection_id + 1 ); assert_eq!( client.connected_to, server_addr.to_socket_addrs().unwrap().next().unwrap() ); iotry!(client.close()); drop(client); }); let mut buf = [0u8; BUF_SIZE]; match server.recv_from(&mut buf) { e => println!("{:?}", e), } // After establishing a new connection, the server's ids are a mirror of the client's. assert_eq!( server.receiver_connection_id, server.sender_connection_id + 1 ); assert_eq!(server.state, SocketState::Closed); drop(server); assert!(child.join().is_ok()); } #[test] fn test_socket_ipv6() { let server_addr = next_test_ip6(); let mut server = iotry!(UtpSocket::bind(server_addr)); assert_eq!(server.state, SocketState::New); let child = thread::spawn(move || { let mut client = iotry!(UtpSocket::connect(server_addr)); assert_eq!(client.state, SocketState::Connected); // Check proper difference in client's send connection id and receive connection id assert_eq!( client.sender_connection_id, client.receiver_connection_id + 1 ); assert_eq!( client.connected_to, server_addr.to_socket_addrs().unwrap().next().unwrap() ); iotry!(client.close()); drop(client); }); let mut buf = [0u8; BUF_SIZE]; match server.recv_from(&mut buf) { e => println!("{:?}", e), } // After establishing a new connection, the server's ids are a mirror of the client's. assert_eq!( server.receiver_connection_id, server.sender_connection_id + 1 ); assert_eq!(server.state, SocketState::Closed); drop(server); assert!(child.join().is_ok()); } #[test] fn test_recvfrom_on_closed_socket() { let server_addr = next_test_ip4(); let mut server = iotry!(UtpSocket::bind(server_addr)); assert_eq!(server.state, SocketState::New); let child = thread::spawn(move || { let mut client = iotry!(UtpSocket::connect(server_addr)); assert_eq!(client.state, SocketState::Connected); assert!(client.close().is_ok()); }); // Make the server listen for incoming connections until the end of the input let mut buf = [0u8; BUF_SIZE]; let _resp = server.recv_from(&mut buf); assert_eq!(server.state, SocketState::Closed); // Trying to receive again returns `Ok(0)` (equivalent to the old `EndOfFile`) match server.recv_from(&mut buf) { Ok((0, _src)) => {} e => panic!("Expected Ok(0), got {:?}", e), } assert_eq!(server.state, SocketState::Closed); assert!(child.join().is_ok()); } #[test] fn test_sendto_on_closed_socket() { let server_addr = next_test_ip4(); let mut server = iotry!(UtpSocket::bind(server_addr)); assert_eq!(server.state, SocketState::New); let child = thread::spawn(move || { let mut client = iotry!(UtpSocket::connect(server_addr)); assert_eq!(client.state, SocketState::Connected); iotry!(client.close()); }); // Make the server listen for incoming connections let mut buf = [0u8; BUF_SIZE]; let (_read, _src) = iotry!(server.recv_from(&mut buf)); assert_eq!(server.state, SocketState::Closed); // Trying to send to the socket after closing it raises an error match server.send_to(&buf) { Err(ref e) if e.kind() == ErrorKind::NotConnected => (), v => panic!("expected {:?}, got {:?}", ErrorKind::NotConnected, v), } assert!(child.join().is_ok()); } #[test] fn test_acks_on_socket() { use std::sync::mpsc::channel; let server_addr = next_test_ip4(); let (tx, rx) = channel(); let mut server = iotry!(UtpSocket::bind(server_addr)); let child = thread::spawn(move || { // Make the server listen for incoming connections let mut buf = [0u8; BUF_SIZE]; let _resp = server.recv(&mut buf); tx.send(server.seq_nr).unwrap(); // Close the connection iotry!(server.recv_from(&mut buf)); drop(server); }); let mut client = iotry!(UtpSocket::connect(server_addr)); assert_eq!(client.state, SocketState::Connected); let sender_seq_nr = rx.recv().unwrap(); let ack_nr = client.ack_nr; assert_eq!(ack_nr, sender_seq_nr); assert!(client.close().is_ok()); // The reply to both connect (SYN) and close (FIN) should be // STATE packets, which don't increase the sequence number // and, hence, the receiver's acknowledgement number. assert_eq!(client.ack_nr, ack_nr); drop(client); assert!(child.join().is_ok()); } #[test] fn test_handle_packet() { //fn test_connection_setup() { let initial_connection_id: u16 = rand::random(); let sender_connection_id = initial_connection_id + 1; let (server_addr, client_addr) = ( next_test_ip4().to_socket_addrs().unwrap().next().unwrap(), next_test_ip4().to_socket_addrs().unwrap().next().unwrap(), ); let mut socket = iotry!(UtpSocket::bind(server_addr)); let mut packet = Packet::new(); packet.set_wnd_size(BUF_SIZE as u32); packet.set_type(PacketType::Syn); packet.set_connection_id(initial_connection_id); // Do we have a response? let response = socket.handle_packet(&packet, client_addr); assert!(response.is_ok()); let response = response.unwrap(); assert!(response.is_some()); // Is is of the correct type? let response = response.unwrap(); assert_eq!(response.get_type(), PacketType::State); // Same connection id on both ends during connection establishment assert_eq!(response.connection_id(), packet.connection_id()); // Response acknowledges SYN assert_eq!(response.ack_nr(), packet.seq_nr()); // No payload? assert!(response.payload().is_empty()); //} // --------------------------------- // fn test_connection_usage() { let old_packet = packet; let old_response = response; let mut packet = Packet::new(); packet.set_type(PacketType::Data); packet.set_connection_id(sender_connection_id); packet.set_seq_nr(old_packet.seq_nr() + 1); packet.set_ack_nr(old_response.seq_nr()); let response = socket.handle_packet(&packet, client_addr); assert!(response.is_ok()); let response = response.unwrap(); assert!(response.is_some()); let response = response.unwrap(); assert_eq!(response.get_type(), PacketType::State); // Sender (i.e., who the initiated connection and sent a SYN) has connection id equal to // initial connection id + 1 // Receiver (i.e., who accepted connection) has connection id equal to initial connection id assert_eq!(response.connection_id(), initial_connection_id); assert_eq!(response.connection_id(), packet.connection_id() - 1); // Previous packets should be ack'ed assert_eq!(response.ack_nr(), packet.seq_nr()); // Responses with no payload should not increase the sequence number assert!(response.payload().is_empty()); assert_eq!(response.seq_nr(), old_response.seq_nr()); // } //fn test_connection_teardown() { let old_packet = packet; let old_response = response; let mut packet = Packet::new(); packet.set_type(PacketType::Fin); packet.set_connection_id(sender_connection_id); packet.set_seq_nr(old_packet.seq_nr() + 1); packet.set_ack_nr(old_response.seq_nr()); let response = socket.handle_packet(&packet, client_addr); assert!(response.is_ok()); let response = response.unwrap(); assert!(response.is_some()); let response = response.unwrap(); assert_eq!(response.get_type(), PacketType::State); // FIN packets have no payload but the sequence number shouldn't increase assert_eq!(packet.seq_nr(), old_packet.seq_nr() + 1); // Nor should the ACK packet's sequence number assert_eq!(response.seq_nr(), old_response.seq_nr()); // FIN should be acknowledged assert_eq!(response.ack_nr(), packet.seq_nr()); //} } #[test] fn test_response_to_keepalive_ack() { // Boilerplate test setup let initial_connection_id: u16 = rand::random(); let (server_addr, client_addr) = ( next_test_ip4().to_socket_addrs().unwrap().next().unwrap(), next_test_ip4().to_socket_addrs().unwrap().next().unwrap(), ); let mut socket = iotry!(UtpSocket::bind(server_addr)); // Establish connection let mut packet = Packet::new(); packet.set_wnd_size(BUF_SIZE as u32); packet.set_type(PacketType::Syn); packet.set_connection_id(initial_connection_id); let response = socket.handle_packet(&packet, client_addr); assert!(response.is_ok()); let response = response.unwrap(); assert!(response.is_some()); let response = response.unwrap(); assert_eq!(response.get_type(), PacketType::State); let old_packet = packet; let old_response = response; // Now, send a keepalive packet let mut packet = Packet::new(); packet.set_wnd_size(BUF_SIZE as u32); packet.set_type(PacketType::State); packet.set_connection_id(initial_connection_id); packet.set_seq_nr(old_packet.seq_nr() + 1); packet.set_ack_nr(old_response.seq_nr()); let response = socket.handle_packet(&packet, client_addr); assert!(response.is_ok()); let response = response.unwrap(); assert!(response.is_none()); // Send a second keepalive packet, identical to the previous one let response = socket.handle_packet(&packet, client_addr); assert!(response.is_ok()); let response = response.unwrap(); assert!(response.is_none()); // Mark socket as closed socket.state = SocketState::Closed; } #[test] fn test_response_to_wrong_connection_id() { // Boilerplate test setup let initial_connection_id: u16 = rand::random(); let (server_addr, client_addr) = ( next_test_ip4().to_socket_addrs().unwrap().next().unwrap(), next_test_ip4().to_socket_addrs().unwrap().next().unwrap(), ); let mut socket = iotry!(UtpSocket::bind(server_addr)); // Establish connection let mut packet = Packet::new(); packet.set_wnd_size(BUF_SIZE as u32); packet.set_type(PacketType::Syn); packet.set_connection_id(initial_connection_id); let response = socket.handle_packet(&packet, client_addr); assert!(response.is_ok()); let response = response.unwrap(); assert!(response.is_some()); assert_eq!(response.unwrap().get_type(), PacketType::State); // Now, disrupt connection with a packet with an incorrect connection id let new_connection_id = initial_connection_id.wrapping_mul(2); let mut packet = Packet::new(); packet.set_wnd_size(BUF_SIZE as u32); packet.set_type(PacketType::State); packet.set_connection_id(new_connection_id); let response = socket.handle_packet(&packet, client_addr); assert!(response.is_ok()); let response = response.unwrap(); assert!(response.is_some()); let response = response.unwrap(); assert_eq!(response.get_type(), PacketType::Reset); assert_eq!(response.ack_nr(), packet.seq_nr()); // Mark socket as closed socket.state = SocketState::Closed; } #[test] fn test_unordered_packets() { // Boilerplate test setup let initial_connection_id: u16 = rand::random(); let (server_addr, client_addr) = ( next_test_ip4().to_socket_addrs().unwrap().next().unwrap(), next_test_ip4().to_socket_addrs().unwrap().next().unwrap(), ); let mut socket = iotry!(UtpSocket::bind(server_addr)); // Establish connection let mut packet = Packet::new(); packet.set_wnd_size(BUF_SIZE as u32); packet.set_type(PacketType::Syn); packet.set_connection_id(initial_connection_id); let response = socket.handle_packet(&packet, client_addr); assert!(response.is_ok()); let response = response.unwrap(); assert!(response.is_some()); let response = response.unwrap(); assert_eq!(response.get_type(), PacketType::State); let old_packet = packet; let old_response = response; let mut window: Vec = Vec::new(); // Now, send a keepalive packet let mut packet = Packet::with_payload(&[1, 2, 3]); packet.set_wnd_size(BUF_SIZE as u32); packet.set_connection_id(initial_connection_id); packet.set_seq_nr(old_packet.seq_nr() + 1); packet.set_ack_nr(old_response.seq_nr()); window.push(packet); let mut packet = Packet::with_payload(&[4, 5, 6]); packet.set_wnd_size(BUF_SIZE as u32); packet.set_connection_id(initial_connection_id); packet.set_seq_nr(old_packet.seq_nr() + 2); packet.set_ack_nr(old_response.seq_nr()); window.push(packet); // Send packets in reverse order let response = socket.handle_packet(&window[1], client_addr); assert!(response.is_ok()); let response = response.unwrap(); assert!(response.is_some()); let response = response.unwrap(); assert!(response.ack_nr() != window[1].seq_nr()); let response = socket.handle_packet(&window[0], client_addr); assert!(response.is_ok()); let response = response.unwrap(); assert!(response.is_some()); // Mark socket as closed socket.state = SocketState::Closed; } #[test] fn test_response_to_triple_ack() { let server_addr = next_test_ip4(); let mut server = iotry!(UtpSocket::bind(server_addr)); // Fits in a packet const LEN: usize = 1024; let data = (0..LEN).map(|idx| idx as u8).collect::>(); let d = data.clone(); assert_eq!(LEN, data.len()); let child = thread::spawn(move || { let mut client = iotry!(UtpSocket::connect(server_addr)); iotry!(client.send_to(&d[..])); iotry!(client.close()); }); let mut buf = [0; BUF_SIZE]; // Expect SYN iotry!(server.recv(&mut buf)); // Receive data let data_packet = match server.socket.recv_from(&mut buf) { Ok((read, _src)) => iotry!(Packet::try_from(&buf[..read])), Err(e) => panic!("{}", e), }; assert_eq!(data_packet.get_type(), PacketType::Data); assert_eq!(&data_packet.payload(), &data.as_slice()); assert_eq!(data_packet.payload().len(), data.len()); // Send triple ACK let mut packet = Packet::new(); packet.set_wnd_size(BUF_SIZE as u32); packet.set_type(PacketType::State); packet.set_seq_nr(server.seq_nr); packet.set_ack_nr(data_packet.seq_nr() - 1); packet.set_connection_id(server.sender_connection_id); for _ in 0..3 { iotry!(server.socket.send_to(packet.as_ref(), server.connected_to)); } // Receive data again and check that it's the same we reported as missing let client_addr = server.connected_to; match server.socket.recv_from(&mut buf) { Ok((0, _)) => panic!("Received 0 bytes from socket"), Ok((read, _src)) => { let packet = iotry!(Packet::try_from(&buf[..read])); assert_eq!(packet.get_type(), PacketType::Data); assert_eq!(packet.seq_nr(), data_packet.seq_nr()); assert_eq!(packet.payload(), data_packet.payload()); let response = server.handle_packet(&packet, client_addr); assert!(response.is_ok()); let response = response.unwrap(); assert!(response.is_some()); let response = response.unwrap(); iotry!(server .socket .send_to(response.as_ref(), server.connected_to)); } Err(e) => panic!("{}", e), } // Receive close iotry!(server.recv_from(&mut buf)); assert!(child.join().is_ok()); } #[test] fn test_socket_timeout_request() { let (server_addr, client_addr) = ( next_test_ip4().to_socket_addrs().unwrap().next().unwrap(), next_test_ip4().to_socket_addrs().unwrap().next().unwrap(), ); let client = iotry!(UtpSocket::bind(client_addr)); let mut server = iotry!(UtpSocket::bind(server_addr)); const LEN: usize = 512; let data = (0..LEN).map(|idx| idx as u8).collect::>(); let d = data.clone(); assert_eq!(server.state, SocketState::New); assert_eq!(client.state, SocketState::New); // Check proper difference in client's send connection id and receive connection id assert_eq!( client.sender_connection_id, client.receiver_connection_id + 1 ); let child = thread::spawn(move || { let mut client = iotry!(UtpSocket::connect(server_addr)); assert_eq!(client.state, SocketState::Connected); assert_eq!(client.connected_to, server_addr); iotry!(client.send_to(&d[..])); drop(client); }); let mut buf = [0u8; BUF_SIZE]; server.recv(&mut buf).unwrap(); // After establishing a new connection, the server's ids are a mirror of the client's. assert_eq!( server.receiver_connection_id, server.sender_connection_id + 1 ); assert_eq!(server.state, SocketState::Connected); // Purposefully read from UDP socket directly and discard it, in order // to behave as if the packet was lost and thus trigger the timeout // handling in the *next* call to `UtpSocket.recv_from`. iotry!(server.socket.recv_from(&mut buf)); // Set a much smaller than usual timeout, for quicker test completion server.congestion_timeout = 50; // Now wait for the previously discarded packet loop { match server.recv_from(&mut buf) { Ok((0, _)) => continue, Ok(_) => break, Err(e) => panic!("{}", e), } } drop(server); assert!(child.join().is_ok()); } #[test] fn test_sorted_buffer_insertion() { let server_addr = next_test_ip4(); let mut socket = iotry!(UtpSocket::bind(server_addr)); let mut packet = Packet::new(); packet.set_seq_nr(1); assert!(socket.incoming_buffer.is_empty()); socket.insert_into_buffer(packet.clone()); assert_eq!(socket.incoming_buffer.len(), 1); packet.set_seq_nr(2); packet.set_timestamp(128.into()); socket.insert_into_buffer(packet.clone()); assert_eq!(socket.incoming_buffer.len(), 2); assert_eq!(socket.incoming_buffer[1].seq_nr(), 2); assert_eq!(socket.incoming_buffer[1].timestamp(), 128.into()); packet.set_seq_nr(3); packet.set_timestamp(256.into()); socket.insert_into_buffer(packet.clone()); assert_eq!(socket.incoming_buffer.len(), 3); assert_eq!(socket.incoming_buffer[2].seq_nr(), 3); assert_eq!(socket.incoming_buffer[2].timestamp(), 256.into()); // Replacing a packet with a more recent version doesn't work packet.set_seq_nr(2); packet.set_timestamp(456.into()); socket.insert_into_buffer(packet.clone()); assert_eq!(socket.incoming_buffer.len(), 3); assert_eq!(socket.incoming_buffer[1].seq_nr(), 2); assert_eq!(socket.incoming_buffer[1].timestamp(), 128.into()); } #[test] fn test_duplicate_packet_handling() { let (server_addr, client_addr) = (next_test_ip4(), next_test_ip4()); let client = iotry!(UtpSocket::bind(client_addr)); let mut server = iotry!(UtpSocket::bind(server_addr)); assert_eq!(server.state, SocketState::New); assert_eq!(client.state, SocketState::New); // Check proper difference in client's send connection id and receive connection id assert_eq!( client.sender_connection_id, client.receiver_connection_id + 1 ); let child = thread::spawn(move || { let mut client = iotry!(UtpSocket::connect(server_addr)); assert_eq!(client.state, SocketState::Connected); let mut packet = Packet::with_payload(&[1, 2, 3]); packet.set_wnd_size(BUF_SIZE as u32); packet.set_connection_id(client.sender_connection_id); packet.set_seq_nr(client.seq_nr); packet.set_ack_nr(client.ack_nr); // Send two copies of the packet, with different timestamps for _ in 0..2 { packet.set_timestamp(now_microseconds()); iotry!(client.socket.send_to(packet.as_ref(), server_addr)); } client.seq_nr += 1; // Receive one ACK for _ in 0..1 { let mut buf = [0; BUF_SIZE]; iotry!(client.socket.recv_from(&mut buf)); } iotry!(client.close()); }); let mut buf = [0u8; BUF_SIZE]; iotry!(server.recv(&mut buf)); // After establishing a new connection, the server's ids are a mirror of the client's. assert_eq!( server.receiver_connection_id, server.sender_connection_id + 1 ); assert_eq!(server.state, SocketState::Connected); let expected: Vec = vec![1, 2, 3]; let mut received: Vec = vec![]; loop { match server.recv_from(&mut buf) { Ok((0, _src)) => break, Ok((len, _src)) => received.extend(buf[..len].to_vec()), Err(e) => panic!("{:?}", e), } } assert_eq!(received.len(), expected.len()); assert_eq!(received, expected); assert!(child.join().is_ok()); } #[test] fn test_correct_packet_loss() { let server_addr = next_test_ip4(); let mut server = iotry!(UtpSocket::bind(server_addr)); const LEN: usize = 1024 * 10; let data = (0..LEN).map(|idx| idx as u8).collect::>(); let to_send = data.clone(); let child = thread::spawn(move || { let mut client = iotry!(UtpSocket::connect(server_addr)); // Send everything except the odd chunks let chunks = to_send[..].chunks(BUF_SIZE); let dst = client.connected_to; for (index, chunk) in chunks.enumerate() { let mut packet = Packet::with_payload(chunk); packet.set_seq_nr(client.seq_nr); packet.set_ack_nr(client.ack_nr); packet.set_connection_id(client.sender_connection_id); packet.set_timestamp(now_microseconds()); if index % 2 == 0 { iotry!(client.socket.send_to(packet.as_ref(), dst)); } client.curr_window += packet.len() as u32; client.send_window.push(packet); client.seq_nr += 1; } iotry!(client.close()); }); let mut buf = [0; BUF_SIZE]; let mut received: Vec = vec![]; loop { match server.recv_from(&mut buf) { Ok((0, _src)) => break, Ok((len, _src)) => received.extend(buf[..len].to_vec()), Err(e) => panic!("{}", e), } } assert_eq!(received.len(), data.len()); assert_eq!(received, data); assert!(child.join().is_ok()); } #[test] fn test_tolerance_to_small_buffers() { let server_addr = next_test_ip4(); let mut server = iotry!(UtpSocket::bind(server_addr)); const LEN: usize = 1024; let data = (0..LEN).map(|idx| idx as u8).collect::>(); let to_send = data.clone(); let child = thread::spawn(move || { let mut client = iotry!(UtpSocket::connect(server_addr)); iotry!(client.send_to(&to_send[..])); iotry!(client.close()); }); let mut read = Vec::new(); while server.state != SocketState::Closed { let mut small_buffer = [0; 512]; match server.recv_from(&mut small_buffer) { Ok((0, _src)) => break, Ok((len, _src)) => read.extend(small_buffer[..len].to_vec()), Err(e) => panic!("{}", e), } } assert_eq!(read.len(), data.len()); assert_eq!(read, data); assert!(child.join().is_ok()); } #[test] fn test_sequence_number_rollover() { let (server_addr, client_addr) = (next_test_ip4(), next_test_ip4()); let mut server = iotry!(UtpSocket::bind(server_addr)); const LEN: usize = BUF_SIZE * 4; let data = (0..LEN).map(|idx| idx as u8).collect::>(); let to_send = data.clone(); let child = thread::spawn(move || { let mut client = iotry!(UtpSocket::bind(client_addr)); // Advance socket's sequence number client.seq_nr = ::std::u16::MAX - (to_send.len() / (BUF_SIZE * 2)) as u16; let mut client = iotry!(UtpSocket::connect(server_addr)); // Send enough data to rollover iotry!(client.send_to(&to_send[..])); // Check that the sequence number did rollover assert!(client.seq_nr < 50); // Close connection iotry!(client.close()); }); let mut buf = [0; BUF_SIZE]; let mut received: Vec = vec![]; loop { match server.recv_from(&mut buf) { Ok((0, _src)) => break, Ok((len, _src)) => received.extend(buf[..len].to_vec()), Err(e) => panic!("{}", e), } } assert_eq!(received.len(), data.len()); assert_eq!(received, data); assert!(child.join().is_ok()); } #[test] fn test_drop_unused_socket() { let server_addr = next_test_ip4(); let server = iotry!(UtpSocket::bind(server_addr)); // Explicitly dropping socket. This test should not hang. drop(server); } #[test] fn test_invalid_packet_on_connect() { use std::net::UdpSocket; let server_addr = next_test_ip4(); let server = iotry!(UdpSocket::bind(server_addr)); let child = thread::spawn(move || { let mut buf = [0; BUF_SIZE]; match server.recv_from(&mut buf) { Ok((_len, client_addr)) => { iotry!(server.send_to(&[], client_addr)); } _ => panic!(), } }); match UtpSocket::connect(server_addr) { Err(ref e) if e.kind() == ErrorKind::Other => (), // OK Err(e) => panic!("Expected ErrorKind::Other, got {:?}", e), Ok(_) => panic!("Expected Err, got Ok"), } assert!(child.join().is_ok()); } #[test] fn test_receive_unexpected_reply_type_on_connect() { use std::net::UdpSocket; let server_addr = next_test_ip4(); let server = iotry!(UdpSocket::bind(server_addr)); let child = thread::spawn(move || { let mut buf = [0; BUF_SIZE]; let mut packet = Packet::new(); packet.set_type(PacketType::Data); match server.recv_from(&mut buf) { Ok((_len, client_addr)) => { iotry!(server.send_to(packet.as_ref(), client_addr)); } _ => panic!(), } }); match UtpSocket::connect(server_addr) { Err(ref e) if e.kind() == ErrorKind::ConnectionRefused => (), // OK Err(e) => panic!("Expected ErrorKind::ConnectionRefused, got {:?}", e), Ok(_) => panic!("Expected Err, got Ok"), } assert!(child.join().is_ok()); } #[test] fn test_receiving_syn_on_established_connection() { // Establish connection let server_addr = next_test_ip4(); let mut server = iotry!(UtpSocket::bind(server_addr)); let child = thread::spawn(move || { let mut buf = [0; BUF_SIZE]; loop { match server.recv_from(&mut buf) { Ok((0, _src)) => break, Ok(_) => (), Err(e) => panic!("{:?}", e), } } }); let mut client = iotry!(UtpSocket::connect(server_addr)); let mut packet = Packet::new(); packet.set_wnd_size(BUF_SIZE as u32); packet.set_type(PacketType::Syn); packet.set_connection_id(client.sender_connection_id); packet.set_seq_nr(client.seq_nr); packet.set_ack_nr(client.ack_nr); iotry!(client.socket.send_to(packet.as_ref(), server_addr)); let mut buf = [0; BUF_SIZE]; match client.socket.recv_from(&mut buf) { Ok((len, _src)) => { let reply = Packet::try_from(&buf[..len]).ok().unwrap(); assert_eq!(reply.get_type(), PacketType::Reset); } Err(e) => panic!("{:?}", e), } iotry!(client.close()); assert!(child.join().is_ok()); } #[test] fn test_receiving_reset_on_established_connection() { // Establish connection let server_addr = next_test_ip4(); let mut server = iotry!(UtpSocket::bind(server_addr)); let child = thread::spawn(move || { let client = iotry!(UtpSocket::connect(server_addr)); let mut packet = Packet::new(); packet.set_wnd_size(BUF_SIZE as u32); packet.set_type(PacketType::Reset); packet.set_connection_id(client.sender_connection_id); packet.set_seq_nr(client.seq_nr); packet.set_ack_nr(client.ack_nr); iotry!(client.socket.send_to(packet.as_ref(), server_addr)); let mut buf = [0; BUF_SIZE]; match client.socket.recv_from(&mut buf) { Ok((_len, _src)) => (), Err(e) => panic!("{:?}", e), } }); let mut buf = [0; BUF_SIZE]; loop { match server.recv_from(&mut buf) { Ok((0, _src)) => break, Ok(_) => (), Err(ref e) if e.kind() == ErrorKind::ConnectionReset => return, Err(e) => panic!("{:?}", e), } } assert!(child.join().is_ok()); panic!("Should have received Reset"); } #[cfg(not(windows))] #[test] fn test_premature_fin() { let (server_addr, client_addr) = (next_test_ip4(), next_test_ip4()); let mut server = iotry!(UtpSocket::bind(server_addr)); const LEN: usize = BUF_SIZE * 4; let data = (0..LEN).map(|idx| idx as u8).collect::>(); let to_send = data.clone(); let child = thread::spawn(move || { let mut client = iotry!(UtpSocket::connect(server_addr)); iotry!(client.send_to(&to_send[..])); iotry!(client.close()); }); let mut buf = [0; BUF_SIZE]; // Accept connection iotry!(server.recv(&mut buf)); // Send FIN without acknowledging packets received let mut packet = Packet::new(); packet.set_connection_id(server.sender_connection_id); packet.set_seq_nr(server.seq_nr); packet.set_ack_nr(server.ack_nr); packet.set_timestamp(now_microseconds()); packet.set_type(PacketType::Fin); iotry!(server.socket.send_to(packet.as_ref(), client_addr)); // Receive until end let mut received: Vec = vec![]; loop { match server.recv_from(&mut buf) { Ok((0, _src)) => break, Ok((len, _src)) => received.extend(buf[..len].to_vec()), Err(e) => panic!("{}", e), } } assert_eq!(received.len(), data.len()); assert_eq!(received, data); assert!(child.join().is_ok()); } #[test] fn test_base_delay_calculation() { let minute_in_microseconds = 60 * 10i64.pow(6); let samples = vec![ (0, 10), (1, 8), (2, 12), (3, 7), (minute_in_microseconds + 1, 11), (minute_in_microseconds + 2, 19), (minute_in_microseconds + 3, 9), ]; let addr = next_test_ip4(); let mut socket = UtpSocket::bind(addr).unwrap(); for (timestamp, delay) in samples { socket.update_base_delay(delay.into(), ((timestamp + delay) as u32).into()); } let expected = vec![7i64, 9i64] .into_iter() .map(Into::into) .collect::>(); let actual = socket.base_delays.iter().cloned().collect::>(); assert_eq!(expected, actual); assert_eq!( socket.min_base_delay(), expected.iter().min().cloned().unwrap_or_default() ); } #[test] fn test_local_addr() { let addr = next_test_ip4(); let addr = addr.to_socket_addrs().unwrap().next().unwrap(); let socket = UtpSocket::bind(addr).unwrap(); assert!(socket.local_addr().is_ok()); assert_eq!(socket.local_addr().unwrap(), addr); } #[test] fn test_listener_local_addr() { let addr = next_test_ip4(); let addr = addr.to_socket_addrs().unwrap().next().unwrap(); let listener = UtpListener::bind(addr).unwrap(); assert!(listener.local_addr().is_ok()); assert_eq!(listener.local_addr().unwrap(), addr); } #[test] fn test_peer_addr() { use std::sync::mpsc::channel; let addr = next_test_ip4(); let server_addr = addr.to_socket_addrs().unwrap().next().unwrap(); let mut server = UtpSocket::bind(server_addr).unwrap(); let (tx, rx) = channel(); // `peer_addr` should return an error because the socket isn't connected yet assert!(server.peer_addr().is_err()); let child = thread::spawn(move || { let mut client = iotry!(UtpSocket::connect(server_addr)); let mut buf = [0; 1024]; iotry!(tx.send(client.local_addr())); iotry!(client.recv_from(&mut buf)); }); // Wait for a connection to be established let mut buf = [0; 1024]; iotry!(server.recv(&mut buf)); // `peer_addr` should succeed and be equal to the client's address assert!(server.peer_addr().is_ok()); // The client is expected to be bound to "0.0.0.0", so we can only check if the port is // correct let client_addr = rx.recv().unwrap().unwrap(); assert_eq!(server.peer_addr().unwrap().port(), client_addr.port()); // Close the connection iotry!(server.close()); // `peer_addr` should now return an error because the socket is closed assert!(server.peer_addr().is_err()); assert!(child.join().is_ok()); } #[test] fn test_take_address() { // Expected successes assert!(take_address("0.0.0.0:0").is_ok()); assert!(take_address("[::]:0").is_ok()); assert!(take_address(("0.0.0.0", 0)).is_ok()); assert!(take_address(("::", 0)).is_ok()); assert!(take_address(("1.2.3.4", 5)).is_ok()); // Expected failures assert!(take_address("999.0.0.0:0").is_err()); assert!(take_address("1.2.3.4:70000").is_err()); assert!(take_address("").is_err()); assert!(take_address("this is not an address").is_err()); assert!(take_address("no.dns.resolution.com").is_err()); } // Test reaction to connection loss when sending data packets #[test] fn test_connection_loss_data() { let server_addr = next_test_ip4(); let mut server = iotry!(UtpSocket::bind(server_addr)); // Decrease timeouts for faster tests server.congestion_timeout = 1; let attempts = server.max_retransmission_retries; let child = thread::spawn(move || { let mut client = iotry!(UtpSocket::connect(server_addr)); iotry!(client.send_to(&[0])); // Simulate connection loss by killing the socket. client.state = SocketState::Closed; let socket = client.socket.try_clone().unwrap(); let mut buf = [0; BUF_SIZE]; iotry!(socket.recv_from(&mut buf)); for _ in 0..attempts { match socket.recv_from(&mut buf) { Ok((len, _src)) => assert_eq!( Packet::try_from(&buf[..len]).unwrap().get_type(), PacketType::Data ), Err(e) => panic!("{}", e), } } }); // Drain incoming packets let mut buf = [0; BUF_SIZE]; iotry!(server.recv_from(&mut buf)); iotry!(server.send_to(&[0])); // Try to receive ACKs, time out too many times on flush, and fail with `TimedOut` let mut buf = [0; BUF_SIZE]; match server.recv(&mut buf) { Err(ref e) if e.kind() == ErrorKind::TimedOut => (), x => panic!("Expected Err(TimedOut), got {:?}", x), } assert!(child.join().is_ok()); } // Test reaction to connection loss when sending FIN #[test] fn test_connection_loss_fin() { let server_addr = next_test_ip4(); let mut server = iotry!(UtpSocket::bind(server_addr)); // Decrease timeouts for faster tests server.congestion_timeout = 1; let attempts = server.max_retransmission_retries; let child = thread::spawn(move || { let mut client = iotry!(UtpSocket::connect(server_addr)); iotry!(client.send_to(&[0])); // Simulate connection loss by killing the socket. client.state = SocketState::Closed; let socket = client.socket.try_clone().unwrap(); let mut buf = [0; BUF_SIZE]; iotry!(socket.recv_from(&mut buf)); for _ in 0..attempts { match socket.recv_from(&mut buf) { Ok((len, _src)) => assert_eq!( Packet::try_from(&buf[..len]).unwrap().get_type(), PacketType::Fin ), Err(e) => panic!("{}", e), } } }); // Drain incoming packets let mut buf = [0; BUF_SIZE]; iotry!(server.recv_from(&mut buf)); // Send FIN, time out too many times, and fail with `TimedOut` match server.close() { Err(ref e) if e.kind() == ErrorKind::TimedOut => (), x => panic!("Expected Err(TimedOut), got {:?}", x), } assert!(child.join().is_ok()); } // Test reaction to connection loss when waiting for data packets #[test] fn test_connection_loss_waiting() { let server_addr = next_test_ip4(); let mut server = iotry!(UtpSocket::bind(server_addr)); // Decrease timeouts for faster tests server.congestion_timeout = 1; let attempts = server.max_retransmission_retries; let child = thread::spawn(move || { let mut client = iotry!(UtpSocket::connect(server_addr)); iotry!(client.send_to(&[0])); // Simulate connection loss by killing the socket. client.state = SocketState::Closed; let socket = client.socket.try_clone().unwrap(); let seq_nr = client.seq_nr; let mut buf = [0; BUF_SIZE]; for _ in 0..(3 * attempts) { match socket.recv_from(&mut buf) { Ok((len, _src)) => { let packet = iotry!(Packet::try_from(&buf[..len])); assert_eq!(packet.get_type(), PacketType::State); assert_eq!(packet.ack_nr(), seq_nr - 1); } Err(e) => panic!("{}", e), } } }); // Drain incoming packets let mut buf = [0; BUF_SIZE]; iotry!(server.recv_from(&mut buf)); // Try to receive data, time out too many times, and fail with `TimedOut` let mut buf = [0; BUF_SIZE]; match server.recv_from(&mut buf) { Err(ref e) if e.kind() == ErrorKind::TimedOut => (), x => panic!("Expected Err(TimedOut), got {:?}", x), } assert!(child.join().is_ok()); } } ================================================ FILE: src/stream.rs ================================================ use crate::socket::UtpSocket; use std::io::{Read, Result, Write}; use std::net::{SocketAddr, ToSocketAddrs}; /// A structure that represents a uTP (Micro Transport Protocol) stream between a local socket and a /// remote socket. /// /// The connection will be closed when the value is dropped (either explicitly or when it goes out /// of scope). /// /// The default maximum retransmission retries is 5, which translates to about 16 seconds. It can be /// changed by calling `set_max_retransmission_retries`. Notice that the initial congestion timeout /// is 500 ms and doubles with each timeout. /// /// # Examples /// /// ```no_run /// use utp::UtpStream; /// use std::io::{Read, Write}; /// /// let mut stream = UtpStream::bind("127.0.0.1:1234").expect("Error binding stream"); /// let _ = stream.write(&[1]); /// let _ = stream.read(&mut [0; 1000]); /// ``` pub struct UtpStream { socket: UtpSocket, } impl UtpStream { /// Creates a uTP stream listening on the given address. /// /// The address type can be any implementer of the `ToSocketAddr` trait. See its documentation /// for concrete examples. /// /// If more than one valid address is specified, only the first will be used. pub fn bind(addr: A) -> Result { UtpSocket::bind(addr).map(|s| UtpStream { socket: s }) } /// Opens a uTP connection to a remote host by hostname or IP address. /// /// The address type can be any implementer of the `ToSocketAddr` trait. See its documentation /// for concrete examples. /// /// If more than one valid address is specified, only the first will be used. pub fn connect(dst: A) -> Result { // Port 0 means the operating system gets to choose it UtpSocket::connect(dst).map(|s| UtpStream { socket: s }) } /// Gracefully closes connection to peer. /// /// This method allows both peers to receive all packets still in /// flight. pub fn close(&mut self) -> Result<()> { self.socket.close() } /// Returns the socket address of the local half of this uTP connection. pub fn local_addr(&self) -> Result { self.socket.local_addr() } /// Changes the maximum number of retransmission retries on the underlying socket. pub fn set_max_retransmission_retries(&mut self, n: u32) { self.socket.max_retransmission_retries = n; } } impl Read for UtpStream { fn read(&mut self, buf: &mut [u8]) -> Result { self.socket.recv_from(buf).map(|(read, _src)| read) } } impl Write for UtpStream { fn write(&mut self, buf: &[u8]) -> Result { self.socket.send_to(buf) } fn flush(&mut self) -> Result<()> { self.socket.flush() } } impl From for UtpStream { fn from(socket: UtpSocket) -> Self { UtpStream { socket } } } impl AsMut for UtpStream { fn as_mut(&mut self) -> &mut UtpSocket { &mut self.socket } } ================================================ FILE: src/time.rs ================================================ use num_traits::ToPrimitive; use std::fmt; use std::ops::Sub; use std::time; /// Return current time in microseconds since the UNIX epoch. pub fn now_microseconds() -> Timestamp { let t = time::SystemTime::now() .duration_since(time::UNIX_EPOCH) .unwrap_or_else(|e| e.duration()); (t.as_secs().wrapping_mul(1_000_000) as u32) .wrapping_add(t.subsec_micros()) .into() } #[derive(Debug, Clone, Copy, PartialOrd, PartialEq)] pub struct Timestamp(pub u32); impl Sub for Timestamp { type Output = Delay; fn sub(self, other: Timestamp) -> Delay { Delay(self.0 as i64 - other.0 as i64) } } impl Default for Timestamp { fn default() -> Timestamp { Timestamp(0) } } impl From for Timestamp { fn from(value: u32) -> Timestamp { Timestamp(value) } } impl From for u32 { fn from(value: Timestamp) -> u32 { value.0 } } #[derive(Debug, Copy, Clone, PartialOrd, PartialEq, Ord, Eq)] pub struct Delay(pub i64); impl From for Delay { fn from(value: i64) -> Delay { Delay(value) } } impl From for Delay { fn from(value: u32) -> Delay { Delay(value as i64) } } impl From for u32 { fn from(value: Delay) -> u32 { value.0 as u32 } } impl Default for Delay { fn default() -> Delay { Delay(0) } } impl Sub for Delay { type Output = Delay; fn sub(self, other: Delay) -> Delay { Delay(self.0 - other.0) } } impl fmt::Display for Delay { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "Delay({})", self.0) } } impl ToPrimitive for Delay { fn to_i64(&self) -> Option { Some(self.0) } fn to_u64(&self) -> Option { Some(self.0 as u64) } } ================================================ FILE: src/util.rs ================================================ use num_traits::ToPrimitive; use rand::{self, Rng}; use std::ops::Sub; /// Calculate the exponential weighted moving average for a vector of numbers, with a smoothing /// factor `alpha` between 0 and 1. A higher `alpha` discounts older observations faster. pub fn ewma<'a, T, I>(mut samples: I, alpha: f64) -> f64 where T: ToPrimitive + 'a, I: Iterator, { let first = samples.next().map_or(0.0, |v| v.to_f64().unwrap()); samples .map(|v| v.to_f64().unwrap()) .fold(first, |avg, sample| alpha * sample + (1.0 - alpha) * avg) } /// Returns the absolute difference between two values. pub fn abs_diff, U>(a: T, b: T) -> U { if a > b { a - b } else { b - a } } /// Safely generates two sequential connection identifiers. /// /// This avoids an overflow when the generated receiver identifier is the largest /// representable value in u16 and it is incremented to yield the corresponding sender /// identifier. pub fn generate_sequential_identifiers() -> (u16, u16) { let mut rng = rand::thread_rng(); let id = rng.gen::(); if id.checked_add(1).is_some() { (id, id + 1) } else { (id - 1, id) } } #[cfg(test)] mod test { use crate::util::*; #[test] fn test_ewma_empty_vector() { let empty: Vec = vec![]; let alpha = 1.0 / 3.0; assert_eq!(ewma(empty.iter(), alpha), 0.0); } #[test] fn test_ewma_one_element() { let input = vec![1u32]; let alpha = 1.0 / 3.0; assert_eq!(ewma(input.iter(), alpha), 1.0); } #[test] fn test_exponential_smoothed_moving_average() { let input = (1u32..11).collect::>(); let alpha = 1.0 / 3.0; let expected = [ 1.0, 4.0 / 3.0, 17.0 / 9.0, 70.0 / 27.0, 275.0 / 81.0, 1036.0 / 243.0, 3773.0 / 729.0, 13378.0 / 2187.0, 46439.0 / 6561.0, 158488.0 / 19683.0, ]; assert_eq!(ewma(input.iter(), alpha), expected[expected.len() - 1]); } #[test] fn test_abs_diff() { let a = 10; let b = 5; assert_eq!(abs_diff(a, b), 5); assert_eq!(abs_diff(b, a), 5); } } ================================================ FILE: tests/stream.rs ================================================ use std::io::{Read, Write}; use std::thread; use utp::UtpStream; macro_rules! iotry { ($e:expr) => { match $e { Ok(e) => e, Err(e) => panic!("{}", e), } }; } fn next_test_port() -> u16 { use std::sync::atomic::{AtomicUsize, Ordering}; static NEXT_OFFSET: AtomicUsize = AtomicUsize::new(0); const BASE_PORT: u16 = 9600; BASE_PORT + NEXT_OFFSET.fetch_add(1, Ordering::Relaxed) as u16 } fn next_test_ip4<'a>() -> (&'a str, u16) { ("127.0.0.1", next_test_port()) } fn next_test_ip6<'a>() -> (&'a str, u16) { ("::1", next_test_port()) } #[test] fn test_stream_open_and_close() { let server_addr = next_test_ip4(); let mut server = iotry!(UtpStream::bind(server_addr)); let child = thread::spawn(move || { let mut client = iotry!(UtpStream::connect(server_addr)); iotry!(client.close()); drop(client); }); let mut received = vec![]; iotry!(server.read_to_end(&mut received)); iotry!(server.close()); assert!(child.join().is_ok()); } #[test] fn test_stream_open_and_close_ipv6() { let server_addr = next_test_ip6(); let mut server = iotry!(UtpStream::bind(server_addr)); let child = thread::spawn(move || { let mut client = iotry!(UtpStream::connect(server_addr)); iotry!(client.close()); drop(client); }); let mut received = vec![]; iotry!(server.read_to_end(&mut received)); iotry!(server.close()); assert!(child.join().is_ok()); } #[test] fn test_stream_small_data() { // Fits in a packet const LEN: usize = 1024; let data: Vec = (0..LEN).map(|idx| idx as u8).collect(); assert_eq!(LEN, data.len()); let d = data.clone(); let server_addr = next_test_ip4(); let mut server = iotry!(UtpStream::bind(server_addr)); let child = thread::spawn(move || { let mut client = iotry!(UtpStream::connect(server_addr)); iotry!(client.write(&d[..])); iotry!(client.close()); }); let mut received = Vec::with_capacity(LEN); iotry!(server.read_to_end(&mut received)); assert!(!received.is_empty()); assert_eq!(received.len(), data.len()); assert_eq!(received, data); assert!(child.join().is_ok()); } #[test] fn test_stream_large_data() { // Has to be sent over several packets const LEN: usize = 1024 * 1024; let data: Vec = (0..LEN).map(|idx| idx as u8).collect(); assert_eq!(LEN, data.len()); let d = data.clone(); let server_addr = next_test_ip4(); let mut server = iotry!(UtpStream::bind(server_addr)); let child = thread::spawn(move || { let mut client = iotry!(UtpStream::connect(server_addr)); iotry!(client.write(&d[..])); iotry!(client.close()); }); let mut received = Vec::with_capacity(LEN); iotry!(server.read_to_end(&mut received)); assert!(!received.is_empty()); assert_eq!(received.len(), data.len()); assert_eq!(received, data); assert!(child.join().is_ok()); } #[test] fn test_stream_successive_reads() { const LEN: usize = 1024; let data: Vec = (0..LEN).map(|idx| idx as u8).collect(); assert_eq!(LEN, data.len()); let d = data.clone(); let server_addr = next_test_ip4(); let mut server = iotry!(UtpStream::bind(server_addr)); let child = thread::spawn(move || { let mut client = iotry!(UtpStream::connect(server_addr)); iotry!(client.write(&d[..])); iotry!(client.close()); }); let mut received = Vec::with_capacity(LEN); iotry!(server.read_to_end(&mut received)); assert!(!received.is_empty()); assert_eq!(received.len(), data.len()); assert_eq!(received, data); assert_eq!(server.read(&mut received).unwrap(), 0); assert!(child.join().is_ok()); } #[test] fn test_local_addr() { use std::net::ToSocketAddrs; let addr = next_test_ip4(); let addr = addr.to_socket_addrs().unwrap().next().unwrap(); let stream = UtpStream::bind(addr).unwrap(); assert!(stream.local_addr().is_ok()); assert_eq!(stream.local_addr().unwrap(), addr); }