A µTP (Micro/uTorrent Transport Library) library implemented in Rust

Overview

rust-utp

Crate Version Build Status Windows Build Status codecov Dependency Status

A Micro Transport Protocol library implemented in Rust.

API documentation

Overview

The Micro Transport Protocol is a reliable transport protocol built over UDP. Its congestion control algorithm is LEDBAT, 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:

[dependencies]
utp = "*"

Then, import it in your crate root or wherever you need it:

extern crate utp;

Examples

The simplest example program would be:

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 <example_name>.

Roadmap

  • congestion control
  • proper connection closing
    • handle both RST and FIN
    • send FIN on close
    • automatically send FIN on drop if not already closed
  • sending RST on mismatch
  • setters and getters that hide header field endianness conversion
  • SACK extension
  • handle packet loss
    • send triple-ACK to re-request lost packet (fast resend request)
    • rewind send window and resend in reply to triple-ACK (fast resend)
    • resend packet on ACK timeout
  • stream interface
  • handle unordered packets
  • duplicate packet handling
  • listener abstraction
  • incoming connections iterator
  • 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.

Comments
  • Small enhancements please

    Small enhancements please

    Some really small stuff:

    • I can't convert an existing UtpSocket into a UtpStream (no suitable constructor).
    • If I bind to 0.0.0.0:0, the underlying UdpSocket will choose a random port. I have no way of retrieving that random port allocation from UtpSocket nor UtpListener currently.
    • UtpListener::accept() doesn't return a (UtpSocket, SocketAddr) like TcpListener does.

    Thanks, Niall

    opened by ned14 9
  • panicked at 'arithmetic operation overflowed'

    panicked at 'arithmetic operation overflowed'

    This line: https://github.com/meqif/rust-utp/blob/88a3aa6410f52eac1a228790c4297b650c1d3274/src/socket.rs#L506

    More info: https://github.com/maidsafe/crust/issues/372

    We've ran into 'arithmetic operation overflowed' from rust-utp before (just needed to let it execute longe enough), but the new rendezvous code we added started to show the problem much more frequently.

    opened by vinipsmaker 7
  • Add read timeout to socket.

    Add read timeout to socket.

    Currently, all reads from the underlying UDP are blocking. This raises several problems, such as:

    • no timeout detection on ACKs for sent packets (which need to be resent),
    • no timeout detection on receive (which may signal a dead connection),
    • no timeout detection on close (meaning a socket may hang in the SocketState::FinSent state indefinitely).

    This branch pull request creates a sub-crate with a new trait, WithReadTimeout, implemented for UdpSocket, adding the method recv_timeout(&mut [u8], i64) to it. This method is only properly implemented for POSIX targets, with the Windows implementation being a dummy which ignores the timeout.

    opened by meqif 5
  • Is there a plan to switch to MIO?

    Is there a plan to switch to MIO?

    Hi Ricardo, this isn't really an "issue", just a question we have so feel free to close it. But, is there a plan to switch rust-utp to mio? I assume it would be a lot of rewrite, both, internally and also to the external API. Or do you think it would make more sense to start from scratch with a new library?

    opened by inetic 3
  • fixes Windows build

    fixes Windows build

    The fixed error is:

    src\with_read_timeout.rs:40:13: 40:19 error: unresolved import `select::fd_set`. Maybe a missing `extern crate select`? [E0432]
    src\with_read_timeout.rs:40         use select::fd_set;
                                            ^~~~~~
    src\with_read_timeout.rs:40:13: 40:19 help: run `rustc --explain E0432` to see a detailed explanation
    error: aborting due to previous error
    

    Introduced in commit dfd91141a0c864bd939d9e0f9cd2ff578aeea2f8

    Hint taken from https://github.com/maidsafe/rust-utp/commit/c7a7190b53488cc1f132bc55a6686c3990370409#diff-b4aea3e418ccdb71239b96952d9cddb6R81

    opened by vinipsmaker 3
  • Unable to concurrently send and receive without racing

    Unable to concurrently send and receive without racing

    We're trying to use rust-utp in https://github.com/maidsafe/crust but we have the problem that we need to send data whilst also concurrently waiting for new data to arrive. The obvious fix is a mutex per UtpSocket which is unlocked while udpsocket.recv_from() to allow sends and other operations to run.

    If you're not able to do it yourself promptly, would you be interested in a pull request, or is there a better way than the above?

    Thanks, Niall

    opened by ned14 3
  • Remove custom socket timeout implementation

    Remove custom socket timeout implementation

    Now that the UDP socket in the standard Rust library reacquired the timeout functions, the old and buggy custom socket timeout implementation can be removed.

    Fixes #19. Waiting on Rust 1.4.

    opened by meqif 2
  • Improve examples

    Improve examples

    Improve code examples in README and module documentation.

    The improvements require result_expect (rust-lang/rust#27277), which is available on Rust 1.4 onwards. Merge only when 1.4 is released as stable.

    opened by meqif 2
  • Upgrade to 2018 edition

    Upgrade to 2018 edition

    Hi there!

    I'm trying out a project which requires uTP, and I came across your crate - which seems quite complete.

    I've updated the code to match Rust 2018 edition, and I thought you could want contributions to update the lib.

    cheers!

    opened by bltavares 1
  • Force PacketHeader's representation to be predictable

    Force PacketHeader's representation to be predictable

    This PR forces the PacketHeader representation to be #[repr(C)]. This fixes an issue where the compiler might reorder the struct's fields, which would mess up the unsafe cast to an array of bytes.

    Currently waiting for the new Rust 15.0 beta to be released and tested against master.

    Fixes #29

    bug 
    opened by meqif 1
  • Adds failing test test_data_exchange_utp

    Adds failing test test_data_exchange_utp

    Also adds a passing test test_data_exchange_tcp for comparison.

    The uTP test sometimes passes so needs to be run in a loop to make sure it is reproduced. When it passes, it sometimes does so quickly, but it often it takes ~10 seconds to finish.

    When it fails, it looks something like this:

    test socket::test::test_data_exchange_utp ... thread '<unnamed>' panicked at 'Error { repr: Custom(Custom { kind: TimedOut, error: StringError("Connection timed out") }) }', src/socket.rs:2531
    stack backtrace:
       1:     0x7fea7da65540 - sys::backtrace::tracing::imp::write::h5839347184a363c1Tnt
       2:     0x7fea7da67b45 - panicking::log_panic::_<closure>::closure.39955
       3:     0x7fea7da67591 - panicking::log_panic::hcde6d42710304abbWnx
       4:     0x7fea7da56da3 - sys_common::unwind::begin_unwind_inner::h4039843fef6bffefYgs
       5:     0x7fea7da57418 - sys_common::unwind::begin_unwind_fmt::hbbea9d3fc97574084fs
       6:     0x7fea7d9fe3e5 - socket::test::test_data_exchange_utp::_<closure>::closure.19345
                            at /home/peter/work/rust/rust-utp/<std macros>:8
       7:     0x7fea7d9fd61c - std::thread::_<impl>::spawn::_<closure>::_<closure>::closure.19340
                            at ../src/libstd/thread/mod.rs:271
       8:     0x7fea7d9fd5d9 - sys_common::unwind::try::try_fn::try_fn::h1429149916602116162
                            at ../src/libstd/sys/common/unwind/mod.rs:156
       9:     0x7fea7da64a78 - __rust_try
      10:     0x7fea7da611eb - sys_common::unwind::try::inner_try::h81e998e565f2181dwds
      11:     0x7fea7d9fd586 - sys_common::unwind::try::try::h5500681879419574301
                            at ../src/libstd/sys/common/unwind/mod.rs:126
      12:     0x7fea7d9fd3fd - std::thread::_<impl>::spawn::_<closure>::closure.19337
                            at ../src/libstd/thread/mod.rs:271
      13:     0x7fea7d9fe79c - boxed::_<impl>::call_box::call_box::h6452290943018104200
                            at ../src/liballoc/boxed.rs:521
      14:     0x7fea7da66633 - sys::thread::_<impl>::new::thread_start::h0be42f811434f5398Fw
      15:     0x7fea7ca066a9 - start_thread
      16:     0x7fea7d22feec - clone
      17:                0x0 - <unknown>
    thread 'socket::test::test_data_exchange_utp' panicked at 'assertion failed: client_t.join().is_ok()', src/socket.rs:2542
    stack backtrace:
       1:     0x7fea7da65540 - sys::backtrace::tracing::imp::write::h5839347184a363c1Tnt
       2:     0x7fea7da67b45 - panicking::log_panic::_<closure>::closure.39955
       3:     0x7fea7da67591 - panicking::log_panic::hcde6d42710304abbWnx
       4:     0x7fea7da56da3 - sys_common::unwind::begin_unwind_inner::h4039843fef6bffefYgs
       5:     0x7fea7d9441c7 - sys_common::unwind::begin_unwind::begin_unwind::h7653023640623241003
                            at ../src/libstd/sys/common/unwind/mod.rs:224
       6:     0x7fea7d9fc6e7 - socket::test::test_data_exchange_utp::h1d6c8c8760628933ibj
                            at /home/peter/work/rust/rust-utp/<std macros>:3
       7:     0x7fea7da3a2a6 - boxed::_<impl>::call_box::call_box::h575065112849089642
       8:     0x7fea7da3cc7f - sys_common::unwind::try::try_fn::try_fn::h2198980327506938284
       9:     0x7fea7da64a78 - __rust_try
      10:     0x7fea7da611eb - sys_common::unwind::try::inner_try::h81e998e565f2181dwds
      11:     0x7fea7da3d010 - boxed::_<impl>::call_box::call_box::h15791639090073025805
      12:     0x7fea7da66633 - sys::thread::_<impl>::new::thread_start::h0be42f811434f5398Fw
      13:     0x7fea7ca066a9 - start_thread
      14:     0x7fea7d22feec - clone
      15:                0x0 - <unknown>
    

    I'm using Ubuntu 15.04 and rustc 1.6.0-nightly (1a2eaffb6 2015-10-31).

    opened by inetic 1
  • ignore expected errors on Windows

    ignore expected errors on Windows

    On Windows, the recv_from operation on the UDP socket may return the following errors, which are expected and should be ignored:

    • 10054 (WSAECONNRESET): Windows can send this error if a previous send operation resulted in an ICMP Port Unreachable. And if it's a loopback interface, it can know whether there is already another end to communicate.
    • 10040 (WSAEMSGSIZE): This error was randomly appearing in a test that I conducted. Not really sure why it's happening. The frequency decreased when I increased the receive buffer size, but it was not important to get a network up and running.

    Without these changes, it was impossible to get a relatively large network running without issues. By large I mean a test that might be too bursting for a single machine to run.

    More references:

    • http://stackoverflow.com/questions/30749423/is-winsock-error-10054-wsaeconnreset-normal-with-udp-to-from-localhost#comment49588739_30749423
    • https://github.com/maidsafe/crust/pull/454
    opened by vinipsmaker 2
  • add read timeout

    add read timeout

    This commit adds a set_read_timeout function similar to Rust's set_read_timeout[1]. The differences compared to upstream are:

    • Operation always succeed.
    • It takes an i64 instead Duration.

    [1] https://doc.rust-lang.org/nightly/std/net/struct.UdpSocket.html#method.set_read_timeout

    opened by vinipsmaker 4
  • Added connection timeouts.

    Added connection timeouts.

    Your earlier code doesn't retry a socket read receiving EINTR, plus I need connections to die if they are not live. I therefore added a loop of all reads with CONNECTION_TIMEOUT which is 20 secs, as it is for TCP on Linux.

    opened by ned14 11
  • CloneableSocket recv() not understanding closed connections

    CloneableSocket recv() not understanding closed connections

    I am calling close() on a CloneableSocket but it does not appear to cause reads in the other side CloneableSocket to exit with an Err. This is because CloneableSocket's recv() is missing the same closed connection detection logic as UtpSocket's recv_form().

    The other thing we need is to detect ungraceful connection close. Either a heartbeat, or a timeout since last packet received would work.

    opened by ned14 5
  • Concurrent reads and writes

    Concurrent reads and writes

    Currently rust-utp doesn't allow concurrent reads and writes to the same socket. This limits its usefulness in a production context.

    Ways to achieve concurrency

    1. Synchronize socket state access/modification and allow cloning,
    2. Split UtpSocket into reading and writing halves, and return those instead of a unified socket,
    3. Spawn a thread inside UtpSocket or UtpStream to wait for incoming packets on the underlying UDP socket.
    opened by meqif 9
Owner
Ricardo Martins
Ricardo Martins
Rosenpass is a formally verified, post-quantum secure VPN that uses WireGuard to transport the actual data.

Rosenpass README This repository contains A description of the Rosenpass protocol The reference implementation of the protocol – the rosenpass tool A

Rosenpass 597 Mar 19, 2023
A Constrained Application Protocol(CoAP) library implemented in Rust.

coap-rs A fast and stable Constrained Application Protocol(CoAP) library implemented in Rust. Features: CoAP core protocol RFC 7252 CoAP Observe optio

Covertness 170 Dec 19, 2022
A generic Rust based Bigtable connection library implemented using gRPC

A generic Rust based Bigtable connection library refactored out the solana mono-repo so that can be shared for different applications.

Lijun Wang 3 Sep 25, 2022
Simple VPN implemented using rust

fubuki Simple VPN implemented using rust fubuki是类似与tincVPN的简单组网工具 不支持对等NAT 支持的平台: Windows Linux 工作机制 它由一台拥有公网IP的服务器来维持各个内网客户端的实际地址映射,在客户端和客户端之间实现P2P通信

XTY 84 Dec 31, 2022
TeleMQ is an experimental MQTT broker implemented in Rust language.

TeleMQ TeleMQ is an experimental MQTT broker implemented in Rust language. The broker implements MQTT version 3.1.1 specification. License This projec

null 12 Dec 27, 2022
A minimal ngrok liked reverse proxy implemented in Rust.

rok A minimal ngrok implementation in Rust, for educational purpose. This work is largely based on rathole, especially the very first commit. Other ho

Kai 3 Jun 21, 2022
Nacos server re-implemented in Rust.

rnacos 简介 rnacos是一个用rust实现的nacos服务。 rnacos是一个轻量、快速、稳定的服务,包含注册中心、配置中心、web管理控制台功能。 rnacos兼容nacos client sdk用到的协议(包含1.x的http OpenApi,和2.x的grpc协议),支持使用nac

heqingpan 18 Jun 7, 2023
The gRPC library for Rust built on C Core library and futures

gRPC-rs gRPC-rs is a Rust wrapper of gRPC Core. gRPC is a high performance, open source universal RPC framework that puts mobile and HTTP/2 first. Sta

TiKV Project 1.6k Jan 7, 2023
A library to work with CIDRs in rust

ipnetwork This is a library to work with IPv4 and IPv6 CIDRs in Rust Run Clippy by doing rustup component add clippy cargo clippy Installation This c

Abhishek Chanda 98 Dec 12, 2022
Nanomsg library for Rust

Nanomsg Documentation Nanomsg is a modern messaging library that is the successor to ZeroMQ, written in C by Martin Sustrik and colleagues. The nanoms

Daniel Fagnan 371 Nov 18, 2022
Backroll is a pure Rust implementation of GGPO rollback networking library.

backroll-rs Backroll is a pure Rust implementation of GGPO rollback networking library. Development Status This is still in an untested alpha stage. A

Hourai Teahouse 273 Dec 28, 2022
A Rust library for parsing the SOME/IP network protocol (without payload interpretation).

someip_parse A Rust library for parsing the SOME/IP network protocol (without payload interpretation). Usage Add the following to your Cargo.toml: [de

Julian Schmid 18 Oct 31, 2022
A library for easily creating WebRTC data channel connections in Rust

Cyberdeck A library for easily creating WebRTC data channel connections in Rust.

RICHΛRD ΛNΛYΛ 34 Nov 10, 2022
Modrinth API is a simple library for using Modrinth's API in Rust projects

Ferinth is a simple library for using the Modrinth API in Rust projects. It uses reqwest as its HTTP(S) client and deserialises responses to typed structs using serde.

null 20 Dec 8, 2022
An LV2 host library for Rust.

Livi A library for hosting LV2 plugins. Note: This is a work in progress and has not yet been full tested. Supported LV2 Features LV2 has a simple cor

Will 11 Nov 8, 2022
A Rust compiler plugin and support library to annotate overflow behavior

overflower This project contains a compiler plugin and supporting library to allow the programmer to annotate their code to declare how integer overfl

null 104 Nov 28, 2022
Dav-server-rs - Rust WebDAV server library. A fork of the webdav-handler crate.

dav-server-rs A fork of the webdav-handler-rs project. Generic async HTTP/Webdav handler Webdav (RFC4918) is defined as HTTP (GET/HEAD/PUT/DELETE) plu

messense 30 Dec 29, 2022
Peer-to-peer communications library for Rust based on QUIC protocol

qp2p Crate Documentation MaidSafe website SAFE Dev Forum SAFE Network Forum Overview This library provides an API to simplify common tasks when creati

MaidSafe 337 Dec 14, 2022
A BitTorrent V1 engine library for Rust (and currently Linux)

cratetorrent Cratetorrent is a Rust crate implementing the BitTorrent version 1 protocol. It can be used as a library and also provides a simple examp

null 401 Dec 28, 2022