-
-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
14 changed files
with
459 additions
and
72 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
github: crazyscot | ||
ko_fi: rossyounger | ||
buy_me_a_coffee: rossyounger | ||
# custom: [] # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,110 @@ | ||
The Quic Copier (`qcp`) is an experimental | ||
high-performance remote file copy utility for long-distance internet connections. | ||
|
||
[//]: # (TODO: Badges, after first publication. Crates, docs, ci, license.) | ||
|
||
## 📋 Features | ||
|
||
- 🔧 Drop-in replacement for `scp` or `rcp` | ||
- 🛡️ Similar security to `scp`, using existing, well-known mechanisms | ||
- 🚀 Better throughput on congested networks | ||
|
||
#### Platform support status | ||
|
||
- Well tested: Debian and Ubuntu using OpenSSH | ||
- Tested: Ubuntu on WSL | ||
- Untested: OSX/BSD family | ||
- Not currently supported: Windows | ||
|
||
## 🧰 Getting Started | ||
|
||
* You must have ssh access to the target machine. | ||
* Install the `qcp` binary on both machines. It needs to be in your `PATH` on the remote machine. | ||
* Run `qcp --help-buffers` and follow its instructions. | ||
|
||
Install it from crates.io using `cargo`: | ||
|
||
```bash | ||
cargo install qcp | ||
``` | ||
|
||
Or, clone the repo and build it manually: | ||
|
||
```bash | ||
git clone https://github.com/crazyscot/qcp | ||
cd qcp | ||
cargo build --release --locked | ||
``` | ||
|
||
#### If you are new to Rust and don't have the tools installed | ||
|
||
* Install the `rustup` tool via your package manager, or see [Rust installation](https://www.rust-lang.org/tools/install) | ||
* `rustup toolchain install stable` | ||
* Proceed as above | ||
|
||
## ⚙️ Usage | ||
|
||
The basic syntax is the same as scp or rcp. | ||
|
||
You can run the program like this: | ||
|
||
```bash | ||
$ qcp my-server:/tmp/testfile /tmp/ | ||
⠂ Transferring data, instant rate: 2.1MB/s | ||
testfile ████████████████████████████████████░░░░░░░░░░░░░░░░░░░░░░░░ 1s @ 6.71 MB/s [60%/10.49 MB] | ||
``` | ||
|
||
The program uses ssh to connect to the target machine and run `qcp --server`. ssh will check the remote host key and prompt you for a password or passphrase in the usual way. | ||
|
||
The default options are for a 100Mbit connection, with 300ms round-trip time to the target server. | ||
|
||
You may care to set the options for your internet connection. For example, if you have 300Mbit/s (37.5MB/s) download and 100Mbit/s (12.5MB/s) upload: | ||
|
||
```bash | ||
qcp my-server:/tmp/testfile /tmp/ --tx 12M --rx 37M | ||
``` | ||
|
||
[//]: # (TODO: link to crates.rs: Performance is a tricky subject, more fully discussed in ...) | ||
|
||
## ⚖️ License | ||
|
||
The initial release is made under the [GNU Affero General Public License](LICENSE). | ||
|
||
## 🧑🏭 Contributing | ||
|
||
Feel free to report bugs via the [bug tracker]. | ||
|
||
I'd particularly welcome performance reports from BSD/OSX users as that's not a platform I use regularly. | ||
|
||
While suggestions and feature requests are welcome, please be aware that I mostly work on this project in my own time. | ||
|
||
## 💸 Supporting the project | ||
|
||
If you find this software useful and would like to support me, please consider [buying me a coffee] (or via [ko-fi]). | ||
|
||
If you're a business and need a formal invoice for your accountant, my freelancing company can issue the paperwork. For this, and any other commercial enquiries (alternative licensing, support, sponsoring features) please get in touch. | ||
|
||
Please also consider supporting the galaxy of projects this work builds upon. | ||
Most notably, [Quinn] is a pure-Rust implementation of the [QUIC] protocol, without which qcp simply wouldn't exist in its current form. | ||
|
||
### 💡 Roadmap | ||
|
||
Some ideas for the future, in no particular order: | ||
|
||
* A local config mechanism, so you don't have to type out the network parameters every time | ||
* Support for copying multiple files (e.g. shell globs or `scp -r`) | ||
* Windows native support, at least for client mode | ||
* Firewall/NAT traversal | ||
* Interactive file transfer (akin to `ftp`) | ||
* Smart file copy using the `rsync` protocol or similar (send only the sections you need to) | ||
* Graphical interface for ftp mode | ||
* Review the protocol and perhaps pivot to using capnp RPC | ||
* Bind a daemon to a fixed port, for better firewall/NAT traversal properties but at the cost of having to implement user authentication. | ||
* _The same thing we do every night, Pinky. We try to take over the world!_ | ||
|
||
[bug tracker]: https://github.com/crazyscot/qcp/issues | ||
[quic]: https://quicwg.github.io/ | ||
[Quinn]: https://opencollective.com/quinn-rs | ||
[rfc9000]: https://www.rfc-editor.org/rfc/rfc9000.html | ||
[buying me a coffee]: https://buymeacoffee.com/rossyounger | ||
[ko-fi]: https://ko-fi.com/rossyounger |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,4 @@ | ||
//! qcp Client parameters | ||
//! Parameters specific to qcp client-mode | ||
// (c) 2024 Ross Younger | ||
|
||
use clap::Parser; | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
//! 📖 Additional documentation | ||
pub mod performance; | ||
pub mod troubleshooting; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
// (c) 2024 Ross Younger | ||
|
||
//! # 🚀 Performance tuning | ||
//! | ||
//! There's probably a whole book to be written about this. | ||
//! | ||
//! I've spent some time tuning this for my use case and leave some hooks so you can experiment. | ||
//! | ||
//! **It is critical to understand that the Internet is a strange place with many variables, which will likely confound any experiment you may try.** | ||
//! | ||
//! In my experience, long-distance traffic flows vary wildly from second to second. | ||
//! This is why I added a near-instant (last 1s) bandwidth readout, as well the average. | ||
//! | ||
//! I found that the throughput from my build server (data flow from Europe to NZ) is sometimes very | ||
//! fast, able to saturate my 300Mbit last-mile downlink, and sometimes falls back to hundreds of | ||
//! kilobits or even worse. But the way QUIC applies congestion control worked around this really well. | ||
//! Throughput accelerates rapidly when congestion clears; I _think_ this is subjectively much faster than scp does, but I've not yet gathered the data to do a proper statistical analysis. | ||
//! | ||
//! Yes, it's inefficient to do an ssh handshake and then a QUIC/TLS handshake. | ||
//! But the cost of doing so isn't much in absolute terms (sometimes a few seconds), | ||
//! and this amortises nicely over a large file transfer. | ||
//! | ||
//! ### Tips | ||
//! | ||
//! * When qcp tells you to set up the kernel UDP buffers, do so; they really make a difference. **You need to do this on both machines.** | ||
//! * Run `qcp -h` and study the network tuning options available to you. | ||
//! * With bandwidth and RTT - at least on my network conditions - I've found that perfect accuracy of configuration isn't so important, as long as it's in the right ballpark. | ||
//! * In many cases your _last-mile_ bandwidth, i.e. whatever you're paying your ISP for, | ||
//! is a good setting to use. | ||
//! But there's a trap here: ISPs often describe their packages in bits per second, | ||
//! but qcp expects a configuration in bytes! | ||
//! * Try out `--congestion bbr` if you like. Sometimes it helps. | ||
//! But understand that it remains experimental, and it does send out a lot more packets. | ||
//! _If you have a metered connection, this may be an issue!_ | ||
//! [More about BBR](https://github.com/google/bbr/blob/master/Documentation/bbr-faq.md). | ||
//! * Mess with the initial congestion window if you like, but I didn't find it reliably useful. | ||
//! * Watch out for either end becoming CPU bound. One of my test machines on my local LAN was unable to move more than 7MB/s. It turned out that its CPU was so old it didn't have a useful crypto accelerator. If that applies to you, unfortunately you're not going to be able to move data any faster without a hardware upgrade. | ||
//! * If you want to copy multiple files to/from the same remote machine, ssh connection multiplexing will save you a few seconds for each. (You can visualise the difference with the `--profile` option.) | ||
//! * The `--debug` option will report additional information that might help you diagnose configuration issues. | ||
//! | ||
//! qcp will report the number of congestion events it detected, unless you run in `-q` mode. | ||
//! | ||
//! You might find it useful to run in `--stats` mode for additional insights; here's the output from a typical run: | ||
//! | ||
//! ```log | ||
//! 2024-10-14T09:20:52.543540Z INFO Transferred 104.9MB in 12.75s; average 8.2MB/s | ||
//! 2024-10-14T09:20:52.543782Z INFO Total packets sent: 3,279 by us; 75,861 by remote | ||
//! 2024-10-14T09:20:52.543955Z WARN Congestion events detected: 2 | ||
//! 2024-10-14T09:20:52.544138Z WARN Remote lost packets: 112/75.9k (0.15%, for 157kB) | ||
//! 2024-10-14T09:20:52.544320Z INFO Path MTU 1452, round-trip time 303.1ms, final congestion window 15,537,114 | ||
//! 2024-10-14T09:20:52.544530Z INFO 3.3k datagrams sent, 75.7k received, 0 black holes detected | ||
//! 2024-10-14T09:20:52.544715Z INFO 107,526,015 total bytes sent for 104,857,600 bytes payload (2.54% overhead/loss) | ||
//! 2024-10-14T09:20:52.544903Z WARN Measured path RTT 303.128843ms was greater than configuration 300; for better performance, next time try --rtt 304 | ||
//! ``` | ||
//! | ||
//! (This was with a 100MB test file, which isn't always enough for the protocol to get fully up to speed.) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
// (c) 2024 Ross Younger | ||
|
||
//! 🕵️ Troubleshooting | ||
//! | ||
//! ## General | ||
//! | ||
//! The `--debug` and `--remote-debug` options report information that may help you diagnose issues. | ||
//! | ||
//! This program also understands the `RUST_LOG` environment variable which might let you probe deeper. | ||
//! Some possible settings for this variable are: | ||
//! | ||
//! * `qcp=trace` outputs tracing-level output from this crate | ||
//! * `trace` sets all the Rust components to trace mode, which includes an _awful lot_ of output from quinn (the QUIC implementation). | ||
//! | ||
//! Note that this variable setting applies to the local machine, not the remote. If you arrange to set it on the remote, the output will come back over the ssh channel; **this may impact performance**. | ||
//! | ||
//! ### You can't ssh to the remote machine | ||
//! | ||
//! Sorry, that's a prerequisite. Get that working first, then come back to qcp. | ||
//! | ||
//! qcp calls ssh directly; ssh will prompt you for a password and may invite you to verify the remote host key. | ||
//! | ||
//! ### The QUIC connection times out | ||
//! | ||
//! * Does the remote host firewall inbound UDP connections? | ||
//! If so, you will need to allocate and open up a small range of inbound ports for use by qcp. | ||
//! Use the `--remote-port` option to tell it which. | ||
//! * Is the remote host behind NAT? Sorry, NAT traversal is not currently supported. | ||
//! At best, you might be able to open up a small range of UDP ports on the NAT gateway which are directly forwarded to the target machine. | ||
//! Use the `--remote-port` option to tell it which. | ||
//! * Are outbound UDP packets from the initiator firewalled? | ||
//! You will need to open up some outbound ports; use the `--port` option to tell qcp which. | ||
//! | ||
//! ### Performance is poor? | ||
//! | ||
//! (This became a separate doc. See [performance](super::performance).) | ||
//! | ||
//! ### Excess bandwidth usage | ||
//! | ||
//! This utility is designed to soak up all the bandwidth it can. | ||
//! | ||
//! When there is little packet loss, the overhead is minimal (2-3%). However when packets do go astray, the retransmits can add up. If you use the BBR congestion controller, this will add up much faster as it tries to keep the pipe fuller; I've seen it report over 20% packet loss. | ||
//! | ||
//! If you're on 95th percentile billing, you may need to take this into account. But if you are on that sort of deal, you are hopefully already spending time to understand and optimise your traffic profile. | ||
//! | ||
//! ### Using qcp interferes with video calls / Netflix / VOIP / etc | ||
//! | ||
//! This utility is designed to soak up all the bandwidth it can. | ||
//! | ||
//! QUIC packets are UDP over IP, the same underlying protocol used for streaming video, calls and so forth. | ||
//! They are quite literally competing with any A/V data you may be running. | ||
//! | ||
//! If this bothers you, you might want to look into setting up QoS on your router. | ||
//! | ||
//! There might be some mileage in having qcp try to limit its bandwidth use or tune it to be less aggressive in the face of congestion, but that's not implemented at the moment. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.