├── .github ├── actions-rs │ └── grcov.yml └── workflows │ ├── ci.yml │ └── coverage.yml ├── .gitignore ├── Cargo.toml ├── LICENSE ├── README.md ├── examples ├── binding_over_turn.rs ├── turncli.rs └── turnsrv.rs └── src ├── attribute.rs ├── auth.rs ├── channel_data.rs ├── client ├── allocate.rs ├── auth.rs ├── core.rs ├── mod.rs └── stun_transaction.rs ├── lib.rs ├── server ├── core.rs └── mod.rs ├── transport ├── channel_data.rs ├── mod.rs ├── stun.rs └── udp_over_turn.rs └── turn_message.rs /.github/actions-rs/grcov.yml: -------------------------------------------------------------------------------- 1 | ignore-not-existing: true 2 | ignore: 3 | - "../*" 4 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | # Based on https://github.com/actions-rs/meta/blob/master/recipes/quickstart.md 2 | 3 | name: CI 4 | 5 | on: [push] 6 | 7 | jobs: 8 | check: 9 | name: Check 10 | runs-on: ubuntu-latest 11 | strategy: 12 | matrix: 13 | toolchain: [stable, beta, nightly] 14 | steps: 15 | - name: Checkout sources 16 | uses: actions/checkout@v3 17 | 18 | - name: Install ${{ matrix.toolchain }} toolchain 19 | uses: actions-rs/toolchain@v1 20 | with: 21 | profile: minimal 22 | toolchain: ${{ matrix.toolchain }} 23 | override: true 24 | 25 | - name: Run cargo check 26 | uses: actions-rs/cargo@v1 27 | with: 28 | command: check 29 | args: --all-features --all 30 | 31 | test: 32 | name: Test Suite 33 | runs-on: ubuntu-latest 34 | strategy: 35 | matrix: 36 | toolchain: [stable, beta, nightly] 37 | steps: 38 | - name: Checkout sources 39 | uses: actions/checkout@v3 40 | 41 | - name: Install ${{ matrix.toolchain }} toolchain 42 | uses: actions-rs/toolchain@v1 43 | with: 44 | profile: minimal 45 | toolchain: ${{ matrix.toolchain }} 46 | override: true 47 | 48 | - name: Run cargo test 49 | uses: actions-rs/cargo@v1 50 | with: 51 | command: test 52 | args: --all-features --all 53 | env: 54 | RUST_BACKTRACE: 1 55 | 56 | lints: 57 | name: Lints 58 | runs-on: ubuntu-latest 59 | strategy: 60 | matrix: 61 | toolchain: [stable, beta, nightly] 62 | steps: 63 | - name: Checkout sources 64 | uses: actions/checkout@v3 65 | 66 | - name: Install ${{ matrix.toolchain }} toolchain 67 | uses: actions-rs/toolchain@v1 68 | with: 69 | profile: minimal 70 | toolchain: ${{ matrix.toolchain }} 71 | override: true 72 | components: rustfmt, clippy 73 | 74 | - name: Run cargo fmt 75 | uses: actions-rs/cargo@v1 76 | with: 77 | command: fmt 78 | args: --all -- --check 79 | 80 | - name: Run cargo clippy 81 | uses: actions-rs/cargo@v1 82 | with: 83 | command: clippy 84 | args: --all-features --all -- -D warnings 85 | -------------------------------------------------------------------------------- /.github/workflows/coverage.yml: -------------------------------------------------------------------------------- 1 | # Based on https://github.com/actions-rs/meta/blob/master/recipes/quickstart.md 2 | 3 | name: Coverage 4 | 5 | on: 6 | push: 7 | branches: 8 | - master 9 | 10 | jobs: 11 | grcov: 12 | name: Coverage 13 | runs-on: ubuntu-latest 14 | steps: 15 | - uses: actions/checkout@v3 16 | 17 | - name: Install toolchain 18 | uses: actions-rs/toolchain@v1 19 | with: 20 | toolchain: nightly 21 | override: true 22 | 23 | - name: Execute tests 24 | uses: actions-rs/cargo@v1 25 | with: 26 | command: test 27 | args: --all --all-features 28 | env: 29 | CARGO_INCREMENTAL: 0 30 | RUSTFLAGS: "-Zprofile -Ccodegen-units=1 -Cinline-threshold=0 -Clink-dead-code -Coverflow-checks=off" 31 | 32 | - name: Gather coverage data 33 | id: coverage 34 | uses: actions-rs/grcov@v0.1 35 | 36 | - name: Coveralls upload 37 | uses: coverallsapp/github-action@master 38 | with: 39 | github-token: ${{ secrets.GITHUB_TOKEN }} 40 | parallel: true 41 | path-to-lcov: ${{ steps.coverage.outputs.report }} 42 | 43 | grcov_finalize: 44 | runs-on: ubuntu-latest 45 | needs: grcov 46 | steps: 47 | - name: Coveralls finalization 48 | uses: coverallsapp/github-action@master 49 | with: 50 | github-token: ${{ secrets.GITHUB_TOKEN }} 51 | parallel-finished: true 52 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | Cargo.lock 3 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "rusturn" 3 | version = "0.0.7" 4 | authors = ["Takeru Ohta "] 5 | description = "A Rust implementation of TURN server and client" 6 | homepage = "https://github.com/sile/rusturn" 7 | repository = "https://github.com/sile/rusturn" 8 | readme = "README.md" 9 | keywords = ["TURN"] 10 | categories = ["asynchronous", "network-programming"] 11 | license = "MIT" 12 | edition = "2021" 13 | 14 | [badges] 15 | coveralls = {repository = "sile/rusturn"} 16 | 17 | [dependencies] 18 | bytecodec = "0.4" 19 | factory = "0.1" 20 | fibers = "0.1" 21 | fibers_timeout_queue = "0.1" 22 | fibers_transport = "0.1" 23 | futures = "0.1" 24 | log = "0.4" 25 | rand = "0.8" 26 | rustun = "0.5" 27 | stun_codec = "0.3" 28 | trackable = "1" 29 | 30 | [dev-dependencies] 31 | clap = { version = "4", features = ["derive"] } 32 | env_logger = "0.9" 33 | fibers_global = "0.1.2" 34 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License 2 | 3 | Copyright (c) 2018 Takeru Ohta 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | rusturn 2 | ======= 3 | 4 | [![rusturn](https://img.shields.io/crates/v/rusturn.svg)](https://crates.io/crates/rusturn) 5 | [![Documentation](https://docs.rs/rusturn/badge.svg)](https://docs.rs/rusturn) 6 | [![Actions Status](https://github.com/sile/rusturn/workflows/CI/badge.svg)](https://github.com/sile/rusturn/actions) 7 | [![Coverage Status](https://coveralls.io/repos/github/sile/rusturn/badge.svg?branch=master)](https://coveralls.io/github/sile/rusturn?branch=master) 8 | [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE) 9 | 10 | A Rust implementation of [TURN][RFC 5766] server and client. 11 | 12 | [Documentation](https://docs.rs/rusturn) 13 | 14 | 15 | Examples 16 | -------- 17 | 18 | ```rust 19 | use futures::Future; 20 | use rustun::message::Request; 21 | use rustun::transport::StunUdpTransporter; 22 | use rusturn::auth::AuthParams; 23 | use rusturn::transport::UdpOverTurnTransporter; 24 | use stun_codec::{rfc5389, MessageDecoder, MessageEncoder}; 25 | 26 | let client_auth_params = AuthParams::new("foo", "bar")?; 27 | let server_auth_params = 28 | AuthParams::with_realm_and_nonce("foo", "bar", "baz", "qux")?; 29 | 30 | // STUN server (peer) 31 | let stun_server = fibers_global::execute(rustun::server::UdpServer::start( 32 | fibers_global::handle(), 33 | "127.0.0.1:0".parse().unwrap(), 34 | rustun::server::BindingHandler, 35 | ))?; 36 | let stun_server_addr = stun_server.local_addr(); 37 | fibers_global::spawn(stun_server.map(|_| ()).map_err(|e| panic!("{}", e))); 38 | 39 | // TURN server 40 | let turn_server = fibers_global::execute(rusturn::server::UdpServer::start( 41 | "127.0.0.1:0".parse().unwrap(), 42 | server_auth_params, 43 | ))?; 44 | let turn_server_addr = turn_server.local_addr(); 45 | fibers_global::spawn(turn_server.map_err(|e| panic!("{}", e))); 46 | 47 | // TURN client 48 | let turn_client = fibers_global::execute(rusturn::client::UdpClient::allocate( 49 | turn_server_addr, 50 | client_auth_params 51 | ))?; 52 | let transporter = 53 | UdpOverTurnTransporter::<_, MessageEncoder<_>, MessageDecoder<_>>::new(turn_client); 54 | 55 | // STUN client (over TURN) 56 | let stun_channel = rustun::channel::Channel::new(StunUdpTransporter::new(transporter)); 57 | let stun_client = rustun::client::Client::new(&fibers_global::handle(), stun_channel); 58 | 59 | // BINDING request 60 | let request = Request::::new(rfc5389::methods::BINDING); 61 | let response = fibers_global::execute( 62 | stun_client.call(stun_server_addr, request) 63 | )?; 64 | assert!(response.is_ok(), "{:?}", response); 65 | ``` 66 | 67 | References 68 | ---------- 69 | 70 | - [RFC 5766: Traversal Using Relays around NAT (TURN)][RFC 5766] 71 | 72 | [RFC 5766]: https://tools.ietf.org/html/rfc5766 73 | -------------------------------------------------------------------------------- /examples/binding_over_turn.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] 2 | extern crate trackable; 3 | 4 | use clap::Parser; 5 | use rustun::channel::Channel; 6 | use rustun::client::Client as StunClient; 7 | use rustun::message::Request; 8 | use rustun::transport::StunUdpTransporter; 9 | use rusturn::auth::AuthParams; 10 | use rusturn::client::UdpClient; 11 | use rusturn::transport::UdpOverTurnTransporter; 12 | use std::net::SocketAddr; 13 | use stun_codec::rfc5389; 14 | use stun_codec::{MessageDecoder, MessageEncoder}; 15 | 16 | #[derive(Debug, Parser)] 17 | #[clap(name = "turncli")] 18 | struct Opt { 19 | /// TURN server address. 20 | #[clap(long)] 21 | turn_server: SocketAddr, 22 | 23 | /// STUN server address ("peer" in TURN's terminology). 24 | #[clap(long)] 25 | stun_server: SocketAddr, 26 | 27 | /// TURN username. 28 | #[clap(long, default_value = "foo")] 29 | username: String, 30 | 31 | /// TURN password. 32 | #[clap(long, default_value = "bar")] 33 | password: String, 34 | } 35 | 36 | fn main() -> Result<(), trackable::error::MainError> { 37 | let opt = Opt::parse(); 38 | 39 | let auth_params = track!(AuthParams::new(&opt.username, &opt.password))?; 40 | 41 | let turn_client = track!(fibers_global::execute(UdpClient::allocate( 42 | opt.turn_server, 43 | auth_params 44 | )))?; 45 | let transporter = 46 | UdpOverTurnTransporter::<_, MessageEncoder<_>, MessageDecoder<_>>::new(turn_client); 47 | 48 | let stun_channel = Channel::new(StunUdpTransporter::new(transporter)); 49 | let stun_client = StunClient::new(&fibers_global::handle(), stun_channel); 50 | 51 | let request = Request::::new(rfc5389::methods::BINDING); 52 | let response = track!(fibers_global::execute( 53 | stun_client.call(opt.stun_server, request) 54 | ))?; 55 | println!("{:?}", response); 56 | 57 | Ok(()) 58 | } 59 | -------------------------------------------------------------------------------- /examples/turncli.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] 2 | extern crate trackable; 3 | 4 | use clap::Parser; 5 | use futures::{Async, Future, Poll}; 6 | use rusturn::auth::AuthParams; 7 | use rusturn::client::{wait, Client, UdpClient}; 8 | use rusturn::Error; 9 | use std::io::Read; 10 | use std::net::SocketAddr; 11 | 12 | #[derive(Debug, Parser)] 13 | #[clap(name = "turncli")] 14 | struct Opt { 15 | /// STUN server address. 16 | #[clap(long, default_value = "127.0.0.1:3478")] 17 | server: SocketAddr, 18 | 19 | /// Peer address. 20 | #[clap(long, default_value = "127.0.0.1:2000")] 21 | peer: SocketAddr, 22 | 23 | /// Username. 24 | #[clap(long, default_value = "foo")] 25 | username: String, 26 | 27 | /// Password. 28 | #[clap(long, default_value = "bar")] 29 | password: String, 30 | 31 | /// Whether to send data using `ChannelData` messages. 32 | #[clap(long)] 33 | use_channel_data: bool, 34 | 35 | /// The number of scheduler threads. 36 | #[clap(long, default_value_t = 1)] 37 | thread_count: usize, 38 | } 39 | 40 | fn main() -> Result<(), trackable::error::MainError> { 41 | env_logger::init_from_env( 42 | env_logger::Env::default().filter_or(env_logger::DEFAULT_FILTER_ENV, "info"), 43 | ); 44 | 45 | let opt = Opt::parse(); 46 | track_assert!( 47 | fibers_global::set_thread_count(opt.thread_count), 48 | trackable::error::Failed 49 | ); 50 | 51 | let server_addr = opt.server; 52 | let auth_params = track!(AuthParams::new(&opt.username, &opt.password))?; 53 | let peer = opt.peer; 54 | 55 | let client = track!(fibers_global::execute(UdpClient::allocate( 56 | server_addr, 57 | auth_params 58 | )))?; 59 | eprintln!("# ALLOCATED: server={:?}", server_addr); 60 | 61 | eprintln!("Relay address is {:?}", client.relay_addr()); 62 | 63 | let use_channel_data = opt.use_channel_data; 64 | let client = track!(fibers_global::execute( 65 | wait(client, move |client| if use_channel_data { 66 | client.channel_bind(peer) 67 | } else { 68 | client.create_permission(peer) 69 | }) 70 | .and_then(|(client, result)| result.map(move |_| client)) 71 | ))?; 72 | if use_channel_data { 73 | eprintln!("# CHANNEL BOUND: peer={:?}", peer); 74 | } else { 75 | eprintln!("# PERMISSION CREATED: peer={:?}", peer); 76 | } 77 | 78 | track!(fibers_global::execute(SendRecvLoop { 79 | peer, 80 | client, 81 | stdin: fibers::io::stdin(), 82 | }))?; 83 | 84 | Ok(()) 85 | } 86 | 87 | struct SendRecvLoop { 88 | peer: SocketAddr, 89 | client: UdpClient, 90 | stdin: fibers::io::Stdin, 91 | } 92 | impl Future for SendRecvLoop { 93 | type Item = (); 94 | type Error = Error; 95 | 96 | fn poll(&mut self) -> Poll { 97 | while let Async::Ready(Some((peer, data))) = track!(self.client.poll_recv())? { 98 | println!("# RECV FROM {:?}: {:?}", peer, data); 99 | } 100 | 101 | let mut buf = [0; 1024]; 102 | match self.stdin.read(&mut buf) { 103 | Err(e) => { 104 | if e.kind() != std::io::ErrorKind::WouldBlock { 105 | return Err(track!(Error::from(e))); 106 | } 107 | } 108 | Ok(0) => { 109 | return Ok(Async::Ready(())); 110 | } 111 | Ok(size) => { 112 | let data = Vec::from(&buf[..size]); 113 | track!(self.client.start_send(self.peer, data))?; 114 | } 115 | } 116 | 117 | track!(self.client.poll_send())?; 118 | Ok(Async::NotReady) 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /examples/turnsrv.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] 2 | extern crate trackable; 3 | 4 | use clap::Parser; 5 | use rusturn::auth::AuthParams; 6 | use rusturn::server::UdpServer; 7 | use std::net::SocketAddr; 8 | 9 | #[derive(Debug, Parser)] 10 | #[clap(name = "turnsrv")] 11 | struct Opt { 12 | /// STUN server address. 13 | #[clap(long, default_value = "127.0.0.1:3478")] 14 | server: SocketAddr, 15 | 16 | /// Username. 17 | #[clap(long, default_value = "foo")] 18 | username: String, 19 | 20 | /// Password. 21 | #[clap(long, default_value = "bar")] 22 | password: String, 23 | 24 | /// Realm. 25 | #[clap(long, default_value = "baz")] 26 | realm: String, 27 | 28 | /// Nonce. 29 | #[clap(long, default_value = "qux")] 30 | nonce: String, 31 | } 32 | 33 | fn main() -> Result<(), trackable::error::MainError> { 34 | env_logger::init_from_env( 35 | env_logger::Env::default().filter_or(env_logger::DEFAULT_FILTER_ENV, "info"), 36 | ); 37 | 38 | let opt = Opt::parse(); 39 | 40 | let server_addr = opt.server; 41 | let auth_params = track!(AuthParams::with_realm_and_nonce( 42 | &opt.username, 43 | &opt.password, 44 | &opt.realm, 45 | &opt.nonce 46 | ))?; 47 | 48 | let turn_server = track!(fibers_global::execute(UdpServer::start( 49 | server_addr, 50 | auth_params, 51 | )))?; 52 | track!(fibers_global::execute(turn_server))?; 53 | 54 | Ok(()) 55 | } 56 | -------------------------------------------------------------------------------- /src/attribute.rs: -------------------------------------------------------------------------------- 1 | use stun_codec::rfc5389::attributes::*; 2 | use stun_codec::rfc5766::attributes::*; 3 | 4 | define_attribute_enums!( 5 | Attribute, 6 | AttributeDecoder, 7 | AttributeEncoder, 8 | [ 9 | // RFC 5389 10 | MappedAddress, 11 | Username, 12 | MessageIntegrity, 13 | ErrorCode, 14 | UnknownAttributes, 15 | Realm, 16 | Nonce, 17 | XorMappedAddress, 18 | Software, 19 | AlternateServer, 20 | Fingerprint, 21 | // RFC 5766 22 | ChannelNumber, 23 | Lifetime, 24 | XorPeerAddress, 25 | Data, 26 | XorRelayAddress, 27 | EvenPort, 28 | RequestedTransport, 29 | DontFragment, 30 | ReservationToken 31 | ] 32 | ); 33 | -------------------------------------------------------------------------------- /src/auth.rs: -------------------------------------------------------------------------------- 1 | use crate::attribute::Attribute; 2 | use crate::{Error, ErrorKind, Result}; 3 | use stun_codec::rfc5389; 4 | use stun_codec::Message; 5 | 6 | #[derive(Debug, Clone)] 7 | pub struct AuthParams { 8 | username: rfc5389::attributes::Username, 9 | password: String, 10 | realm: Option, 11 | nonce: Option, 12 | } 13 | impl AuthParams { 14 | pub fn new(username: &str, password: &str) -> Result { 15 | let username = track!(rfc5389::attributes::Username::new(username.to_owned()))?; 16 | Ok(AuthParams { 17 | username, 18 | password: password.to_owned(), 19 | realm: None, 20 | nonce: None, 21 | }) 22 | } 23 | 24 | pub fn with_realm_and_nonce( 25 | username: &str, 26 | password: &str, 27 | realm: &str, 28 | nonce: &str, 29 | ) -> Result { 30 | let username = track!(rfc5389::attributes::Username::new(username.to_owned()))?; 31 | let realm = track!(rfc5389::attributes::Realm::new(realm.to_owned()))?; 32 | let nonce = track!(rfc5389::attributes::Nonce::new(nonce.to_owned()))?; 33 | Ok(AuthParams { 34 | username, 35 | password: password.to_owned(), 36 | realm: Some(realm), 37 | nonce: Some(nonce), 38 | }) 39 | } 40 | 41 | pub fn has_realm(&self) -> bool { 42 | self.realm.is_some() 43 | } 44 | 45 | pub fn has_nonce(&self) -> bool { 46 | self.nonce.is_some() 47 | } 48 | 49 | pub fn set_realm(&mut self, realm: rfc5389::attributes::Realm) { 50 | self.realm = Some(realm); 51 | } 52 | 53 | pub fn set_nonce(&mut self, nonce: rfc5389::attributes::Nonce) { 54 | self.nonce = Some(nonce); 55 | } 56 | 57 | pub fn get_realm(&self) -> Option<&rfc5389::attributes::Realm> { 58 | self.realm.as_ref() 59 | } 60 | 61 | pub fn get_nonce(&self) -> Option<&rfc5389::attributes::Nonce> { 62 | self.nonce.as_ref() 63 | } 64 | 65 | pub fn add_auth_attributes(&self, mut message: T) -> Result<()> 66 | where 67 | T: AsMut>, 68 | { 69 | let realm = track_assert_some!(self.realm.clone(), ErrorKind::Other); 70 | let nonce = track_assert_some!(self.nonce.clone(), ErrorKind::Other); 71 | message.as_mut().add_attribute(self.username.clone()); 72 | message.as_mut().add_attribute(realm.clone()); 73 | message.as_mut().add_attribute(nonce); 74 | let mi = track!( 75 | rfc5389::attributes::MessageIntegrity::new_long_term_credential( 76 | message.as_mut(), 77 | &self.username, 78 | &realm, 79 | &self.password, 80 | ) 81 | )?; 82 | message.as_mut().add_attribute(mi); 83 | Ok(()) 84 | } 85 | 86 | pub fn validate(&self, mi: &rfc5389::attributes::MessageIntegrity) -> Result<()> { 87 | let realm = track_assert_some!(self.realm.as_ref(), ErrorKind::Other); 88 | track!(mi 89 | .check_long_term_credential(&self.username, realm, &self.password) 90 | .map_err(Error::from))?; 91 | Ok(()) 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /src/channel_data.rs: -------------------------------------------------------------------------------- 1 | use bytecodec::bytes::{BytesDecoder, BytesEncoder}; 2 | use bytecodec::combinator::Peekable; 3 | use bytecodec::fixnum::{U16beDecoder, U16beEncoder}; 4 | use bytecodec::{ByteCount, Decode, Encode, Eos, ErrorKind, Result, SizedEncode}; 5 | use stun_codec::rfc5766::attributes::ChannelNumber; 6 | 7 | #[derive(Debug)] 8 | pub struct ChannelData { 9 | channel_number: ChannelNumber, 10 | data: Vec, 11 | } 12 | impl ChannelData { 13 | pub fn new(channel_number: ChannelNumber, data: Vec) -> Result { 14 | track_assert!(data.len() <= 0xFFFF, ErrorKind::InvalidInput; data.len()); 15 | Ok(ChannelData { 16 | channel_number, 17 | data, 18 | }) 19 | } 20 | 21 | pub fn channel_number(&self) -> ChannelNumber { 22 | self.channel_number 23 | } 24 | 25 | pub fn into_data(self) -> Vec { 26 | self.data 27 | } 28 | } 29 | 30 | #[derive(Debug, Default)] 31 | pub struct ChannelDataDecoder { 32 | channel_number: U16beDecoder, 33 | data_len: Peekable, 34 | data: BytesDecoder, 35 | } 36 | impl Decode for ChannelDataDecoder { 37 | type Item = ChannelData; 38 | 39 | fn decode(&mut self, buf: &[u8], eos: Eos) -> Result { 40 | let mut offset = 0; 41 | bytecodec_try_decode!(self.channel_number, offset, buf, eos); 42 | if !self.data_len.is_idle() { 43 | bytecodec_try_decode!(self.data_len, offset, buf, eos); 44 | 45 | let len = self.data_len.peek().cloned().expect("never fails"); 46 | self.data.set_bytes(vec![0; len as usize]); 47 | } 48 | bytecodec_try_decode!(self.data, offset, buf, eos); 49 | Ok(offset) 50 | } 51 | 52 | fn finish_decoding(&mut self) -> Result { 53 | let channel_number = track!(self.channel_number.finish_decoding())?; 54 | let channel_number = track!(ChannelNumber::new(channel_number))?; 55 | let _ = track!(self.data_len.finish_decoding())?; 56 | let data = track!(self.data.finish_decoding())?; 57 | Ok(ChannelData { 58 | channel_number, 59 | data, 60 | }) 61 | } 62 | 63 | fn requiring_bytes(&self) -> ByteCount { 64 | self.channel_number 65 | .requiring_bytes() 66 | .add_for_decoding(self.data_len.requiring_bytes()) 67 | .add_for_decoding(self.data.requiring_bytes()) 68 | } 69 | 70 | fn is_idle(&self) -> bool { 71 | self.channel_number.is_idle() && self.data_len.is_idle() && self.data.is_idle() 72 | } 73 | } 74 | 75 | #[derive(Debug, Default)] 76 | pub struct ChannelDataEncoder { 77 | channel_number: U16beEncoder, 78 | data_len: U16beEncoder, 79 | data: BytesEncoder, 80 | } 81 | impl Encode for ChannelDataEncoder { 82 | type Item = ChannelData; 83 | 84 | fn encode(&mut self, buf: &mut [u8], eos: Eos) -> Result { 85 | let mut offset = 0; 86 | bytecodec_try_encode!(self.channel_number, offset, buf, eos); 87 | bytecodec_try_encode!(self.data_len, offset, buf, eos); 88 | bytecodec_try_encode!(self.data, offset, buf, eos); 89 | Ok(offset) 90 | } 91 | 92 | fn start_encoding(&mut self, item: Self::Item) -> Result<()> { 93 | track!(self 94 | .channel_number 95 | .start_encoding(item.channel_number.value()))?; 96 | track!(self.data_len.start_encoding(item.data.len() as u16))?; 97 | track!(self.data.start_encoding(item.data))?; 98 | Ok(()) 99 | } 100 | 101 | fn requiring_bytes(&self) -> ByteCount { 102 | ByteCount::Finite(self.exact_requiring_bytes()) 103 | } 104 | 105 | fn is_idle(&self) -> bool { 106 | self.channel_number.is_idle() && self.data_len.is_idle() && self.data.is_idle() 107 | } 108 | } 109 | impl SizedEncode for ChannelDataEncoder { 110 | fn exact_requiring_bytes(&self) -> u64 { 111 | self.channel_number.exact_requiring_bytes() 112 | + self.data_len.exact_requiring_bytes() 113 | + self.data.exact_requiring_bytes() 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /src/client/allocate.rs: -------------------------------------------------------------------------------- 1 | use super::core::ClientCore; 2 | use super::stun_transaction::StunTransaction; 3 | use crate::attribute::Attribute; 4 | use crate::auth::AuthParams; 5 | use crate::channel_data::ChannelData; 6 | use crate::{Error, ErrorKind, Result}; 7 | use fibers_transport::Transport; 8 | use futures::{Async, Future, Poll}; 9 | use rustun::channel::Channel as StunChannel; 10 | use rustun::message::{Request, Response}; 11 | use rustun::transport::StunTransport; 12 | use stun_codec::{rfc5389, rfc5766}; 13 | 14 | const TRANSPORT_PROTOCOL_UDP: u8 = 17; 15 | 16 | #[derive(Debug)] 17 | pub struct Allocate 18 | where 19 | S: StunTransport, 20 | { 21 | stun_channel: Option>, 22 | channel_data_transporter: Option, 23 | auth_params: AuthParams, 24 | allocate_transaction: Option, 25 | } 26 | impl Allocate 27 | where 28 | S: StunTransport + 'static, 29 | C: Transport, 30 | { 31 | pub fn new( 32 | stun_channel: StunChannel, 33 | channel_data_transporter: C, 34 | auth_params: AuthParams, 35 | ) -> Self { 36 | Allocate { 37 | stun_channel: Some(stun_channel), 38 | channel_data_transporter: Some(channel_data_transporter), 39 | auth_params, 40 | allocate_transaction: None, 41 | } 42 | } 43 | 44 | fn start_allocate(&mut self) -> Result<()> { 45 | let mut request = Request::new(rfc5766::methods::ALLOCATE); 46 | 47 | let requested_transport = 48 | rfc5766::attributes::RequestedTransport::new(TRANSPORT_PROTOCOL_UDP).into(); 49 | request.add_attribute(requested_transport); 50 | 51 | if self.auth_params.has_realm() { 52 | track!(self.auth_params.add_auth_attributes(&mut request))?; 53 | } 54 | self.allocate_transaction = Some(StunTransaction::new( 55 | self.stun_channel 56 | .as_mut() 57 | .expect("never fails") 58 | .call((), request), 59 | )); 60 | Ok(()) 61 | } 62 | 63 | fn handle_allocate_response( 64 | &mut self, 65 | response: Response, 66 | ) -> Result>> { 67 | match response { 68 | Ok(response) => { 69 | let mut lifetime = None; 70 | let mut relay_addr = None; 71 | for attr in response.attributes() { 72 | match attr { 73 | Attribute::Lifetime(a) => { 74 | lifetime = Some(a.lifetime()); 75 | } 76 | Attribute::MessageIntegrity(a) => { 77 | track!(self.auth_params.validate(a))?; 78 | } 79 | Attribute::XorRelayAddress(a) => { 80 | relay_addr = Some(a.address()); 81 | } 82 | _ => {} 83 | } 84 | } 85 | 86 | let lifetime = track_assert_some!(lifetime, ErrorKind::Other; response); 87 | let client = ClientCore::new( 88 | self.stun_channel.take().expect("never fails"), 89 | self.channel_data_transporter.take().expect("never fails"), 90 | self.auth_params.clone(), 91 | lifetime, 92 | relay_addr, 93 | ); 94 | Ok(Some(client)) 95 | } 96 | Err(response) => { 97 | track_assert!(!self.auth_params.has_realm(), ErrorKind::Other; response); 98 | 99 | for attr in response.attributes() { 100 | match attr { 101 | Attribute::ErrorCode(e) => { 102 | track_assert_eq!(e.code(), rfc5389::errors::Unauthorized::CODEPOINT, 103 | ErrorKind::Other; response); 104 | } 105 | Attribute::Realm(a) => { 106 | self.auth_params.set_realm(a.clone()); 107 | } 108 | Attribute::Nonce(a) => { 109 | self.auth_params.set_nonce(a.clone()); 110 | } 111 | _ => {} 112 | } 113 | } 114 | track_assert!(self.auth_params.has_realm(), ErrorKind::Other; response); 115 | track_assert!(self.auth_params.has_nonce(), ErrorKind::Other; response); 116 | 117 | track!(self.start_allocate())?; 118 | Ok(None) 119 | } 120 | } 121 | } 122 | 123 | fn stun_channel_mut(&mut self) -> &mut StunChannel { 124 | self.stun_channel 125 | .as_mut() 126 | .expect("Cannot poll Allocate twice") 127 | } 128 | 129 | fn channel_data_transporter_mut(&mut self) -> &mut C { 130 | self.channel_data_transporter 131 | .as_mut() 132 | .expect("Cannot poll Allocate twice") 133 | } 134 | } 135 | impl Future for Allocate 136 | where 137 | S: StunTransport + 'static, 138 | C: Transport, 139 | { 140 | type Item = ClientCore; 141 | type Error = Error; 142 | 143 | fn poll(&mut self) -> Poll { 144 | let mut did_something = true; 145 | while did_something { 146 | did_something = false; 147 | 148 | if self.allocate_transaction.is_none() { 149 | did_something = true; 150 | track!(self.start_allocate())?; 151 | } 152 | 153 | if let Async::Ready(message) = track!(self.stun_channel_mut().poll_recv())? { 154 | track_panic!( 155 | ErrorKind::Other, 156 | "Unexpected message reception: {:?}", 157 | message 158 | ); 159 | } 160 | if let Async::Ready(data) = track!(self.channel_data_transporter_mut().poll_recv())? { 161 | track_panic!(ErrorKind::Other, "Unexpected data reception: {:?}", data); 162 | } 163 | track!(self.channel_data_transporter_mut().poll_send())?; 164 | 165 | if let Async::Ready(Some(response)) = track!(self.allocate_transaction.poll())? { 166 | did_something = true; 167 | if let Some(client) = track!(self.handle_allocate_response(response))? { 168 | return Ok(Async::Ready(client)); 169 | } 170 | } 171 | } 172 | Ok(Async::NotReady) 173 | } 174 | } 175 | unsafe impl Send for Allocate where S: StunTransport {} 176 | -------------------------------------------------------------------------------- /src/client/auth.rs: -------------------------------------------------------------------------------- 1 | use stun_codec::rfc5389; 2 | 3 | use Result; 4 | 5 | #[derive(Debug)] 6 | pub struct AuthParams { 7 | username: rfc5389::attributes::Username, 8 | password: String, 9 | } 10 | impl AuthParams { 11 | pub fn new(username: String, password: String) -> Result { 12 | let username = track!(rfc5389::attributes::Username::new(username))?; 13 | Ok(AuthParams { username, password }) 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/client/core.rs: -------------------------------------------------------------------------------- 1 | use super::allocate::Allocate; 2 | use super::stun_transaction::StunTransaction; 3 | use crate::attribute::Attribute; 4 | use crate::auth::AuthParams; 5 | use crate::channel_data::ChannelData; 6 | use crate::{AsyncReply, AsyncResult, Error, ErrorKind, Result}; 7 | use fibers_timeout_queue::TimeoutQueue; 8 | use fibers_transport::Transport; 9 | use futures::{Async, Future, Poll}; 10 | use rustun::channel::{Channel as StunChannel, RecvMessage}; 11 | use rustun::message::{ErrorResponse, Indication, Request, Response}; 12 | use rustun::transport::StunTransport; 13 | use std::collections::HashMap; 14 | use std::net::{IpAddr, SocketAddr}; 15 | use std::time::Duration; 16 | use stun_codec::rfc5766::attributes::ChannelNumber; 17 | use stun_codec::{rfc5389, rfc5766}; 18 | 19 | const PERMISSION_LIFETIME_SECONDS: u64 = 300; 20 | const CHANNEL_LIFETIME_SECONDS: u64 = PERMISSION_LIFETIME_SECONDS; // FIXME: Use `600` (and refresh permissions) 21 | 22 | #[derive(Debug)] 23 | pub struct ClientCore 24 | where 25 | S: StunTransport, 26 | C: Transport, 27 | { 28 | stun_channel: StunChannel, 29 | channel_data_transporter: C, 30 | auth_params: AuthParams, 31 | lifetime: Duration, 32 | permissions: HashMap>>, 33 | channels: HashMap, 34 | next_channel_number: ChannelNumber, 35 | timeout_queue: TimeoutQueue, 36 | refresh_transaction: StunTransaction, 37 | create_permission_transaction: StunTransaction<(SocketAddr, Response)>, 38 | channel_bind_transaction: StunTransaction<(SocketAddr, Response)>, 39 | relay_addr: Option, 40 | } 41 | impl ClientCore 42 | where 43 | S: StunTransport + 'static, 44 | C: Transport, 45 | { 46 | pub fn allocate( 47 | stun_transporter: S, 48 | channel_data_transporter: C, 49 | auth_params: AuthParams, 50 | ) -> Allocate { 51 | Allocate::new( 52 | StunChannel::new(stun_transporter), 53 | channel_data_transporter, 54 | auth_params, 55 | ) 56 | } 57 | 58 | pub fn new( 59 | stun_channel: StunChannel, 60 | channel_data_transporter: C, 61 | auth_params: AuthParams, 62 | lifetime: Duration, 63 | relay_addr: Option, 64 | ) -> Self { 65 | let mut timeout_queue = TimeoutQueue::new(); 66 | timeout_queue.push(TimeoutEntry::Refresh, lifetime * 9 / 10); 67 | ClientCore { 68 | stun_channel, 69 | channel_data_transporter, 70 | auth_params, 71 | lifetime, 72 | permissions: HashMap::new(), 73 | channels: HashMap::new(), 74 | next_channel_number: ChannelNumber::min(), 75 | timeout_queue, 76 | refresh_transaction: StunTransaction::empty(), 77 | create_permission_transaction: StunTransaction::empty(), 78 | channel_bind_transaction: StunTransaction::empty(), 79 | relay_addr, 80 | } 81 | } 82 | 83 | pub fn stun_channel_ref(&self) -> &StunChannel { 84 | &self.stun_channel 85 | } 86 | 87 | pub fn relay_addr(&self) -> Option { 88 | self.relay_addr 89 | } 90 | 91 | fn start_refresh(&mut self) -> Result<()> { 92 | let lifetime = track!(rfc5766::attributes::Lifetime::new(self.lifetime))?; 93 | 94 | let mut request = Request::new(rfc5766::methods::REFRESH); 95 | request.add_attribute(lifetime.into()); 96 | track!(self.auth_params.add_auth_attributes(&mut request))?; 97 | 98 | self.refresh_transaction = StunTransaction::new(self.stun_channel.call((), request)); 99 | Ok(()) 100 | } 101 | 102 | fn handle_refresh_response(&mut self, response: Response) -> Result<()> { 103 | match response { 104 | Err(response) => { 105 | track!(self.handle_error_response(response))?; 106 | track!(self.start_refresh())?; 107 | } 108 | Ok(response) => { 109 | let mut lifetime = None; 110 | for attr in response.attributes() { 111 | match attr { 112 | Attribute::Lifetime(a) => { 113 | lifetime = Some(a.lifetime()); 114 | } 115 | Attribute::MessageIntegrity(a) => { 116 | track!(self.auth_params.validate(a))?; 117 | } 118 | _ => {} 119 | } 120 | } 121 | 122 | self.lifetime = track_assert_some!(lifetime, ErrorKind::Other; response); 123 | self.timeout_queue 124 | .push(TimeoutEntry::Refresh, self.lifetime * 9 / 10); 125 | } 126 | } 127 | Ok(()) 128 | } 129 | 130 | fn handle_create_permission_response( 131 | &mut self, 132 | peer: SocketAddr, 133 | response: Response, 134 | ) -> Result<()> { 135 | let reply = track_assert_some!(self.permissions.remove(&peer.ip()), ErrorKind::Other); 136 | match response { 137 | Err(response) => { 138 | track!(self.handle_error_response(response))?; 139 | if let Err(e) = track!(self.create_permission_inner(peer)) { 140 | if let Some(reply) = reply { 141 | reply.send(Err(e.clone())); 142 | } 143 | return Err(e); 144 | } 145 | self.permissions.insert(peer.ip(), reply); 146 | } 147 | Ok(response) => { 148 | for attr in response.attributes() { 149 | if let Attribute::MessageIntegrity(a) = attr { 150 | track!(self.auth_params.validate(a))?; 151 | } 152 | } 153 | if let Some(reply) = reply { 154 | reply.send(Ok(())); 155 | } 156 | self.permissions.insert(peer.ip(), None); 157 | self.timeout_queue.push( 158 | TimeoutEntry::Permission { peer }, 159 | Duration::from_secs(PERMISSION_LIFETIME_SECONDS * 9 / 10), 160 | ); 161 | } 162 | } 163 | Ok(()) 164 | } 165 | 166 | fn handle_channel_bind_response( 167 | &mut self, 168 | peer: SocketAddr, 169 | response: Response, 170 | ) -> Result<()> { 171 | let state = track_assert_some!(self.channels.remove(&peer), ErrorKind::Other); 172 | match response { 173 | Err(response) => { 174 | track!(self.handle_error_response(response))?; 175 | if let Err(e) = track!(self.channel_bind_inner(peer, state.channel_number())) { 176 | if let ChannelState::Creating { reply, .. } = state { 177 | reply.send(Err(e.clone())); 178 | } 179 | return Err(e); 180 | } 181 | self.channels.insert(peer, state); 182 | } 183 | Ok(response) => { 184 | for attr in response.attributes() { 185 | if let Attribute::MessageIntegrity(a) = attr { 186 | track!(self.auth_params.validate(a))?; 187 | } 188 | } 189 | 190 | let number = state.channel_number(); 191 | if let ChannelState::Creating { reply, .. } = state { 192 | reply.send(Ok(())); 193 | } 194 | self.channels.insert(peer, ChannelState::Created { number }); 195 | self.timeout_queue.push( 196 | TimeoutEntry::Channel { peer }, 197 | Duration::from_secs(CHANNEL_LIFETIME_SECONDS * 9 / 10), 198 | ); 199 | } 200 | } 201 | Ok(()) 202 | } 203 | 204 | fn handle_error_response(&mut self, response: ErrorResponse) -> Result<()> { 205 | let error: &rfc5389::attributes::ErrorCode = 206 | track_assert_some!(response.get_attribute(), ErrorKind::Other; response); 207 | track_assert_eq!( 208 | error.code(), 209 | rfc5389::errors::StaleNonce::CODEPOINT, 210 | ErrorKind::Other; response 211 | ); 212 | 213 | let nonce: &rfc5389::attributes::Nonce = 214 | track_assert_some!(response.get_attribute(), ErrorKind::Other; response); 215 | self.auth_params.set_nonce(nonce.clone()); 216 | 217 | Ok(()) 218 | } 219 | 220 | fn handle_timeout(&mut self, entry: TimeoutEntry) -> Result<()> { 221 | match entry { 222 | TimeoutEntry::Refresh => track!(self.start_refresh())?, 223 | TimeoutEntry::Permission { peer } => { 224 | if self.permissions.remove(&peer.ip()).is_some() { 225 | track!(self.create_permission_inner(peer))?; 226 | self.permissions.insert(peer.ip(), None); 227 | self.timeout_queue.push( 228 | TimeoutEntry::Permission { peer }, 229 | Duration::from_secs(PERMISSION_LIFETIME_SECONDS * 9 / 10), 230 | ); 231 | } 232 | } 233 | TimeoutEntry::Channel { peer } => { 234 | if let Some(state) = self.channels.remove(&peer) { 235 | track!(self.channel_bind_inner(peer, state.channel_number()))?; 236 | self.channels.insert(peer, state); 237 | self.timeout_queue.push( 238 | TimeoutEntry::Channel { peer }, 239 | Duration::from_secs(CHANNEL_LIFETIME_SECONDS * 9 / 10), 240 | ); 241 | } 242 | } 243 | } 244 | Ok(()) 245 | } 246 | 247 | fn handle_stun_message( 248 | &mut self, 249 | message: RecvMessage, 250 | ) -> Result)>> { 251 | match message { 252 | RecvMessage::Invalid(message) => track_panic!(ErrorKind::Other; message), 253 | RecvMessage::Request(request) => track_panic!(ErrorKind::Other; request), 254 | RecvMessage::Indication(indication) => track!(self.handle_stun_indication(indication)), 255 | } 256 | } 257 | 258 | fn handle_stun_indication( 259 | &mut self, 260 | indication: Indication, 261 | ) -> Result)>> { 262 | match indication.method() { 263 | rfc5766::methods::DATA => { 264 | let data: &rfc5766::attributes::Data = 265 | track_assert_some!(indication.get_attribute(), ErrorKind::Other; indication); 266 | let peer: &rfc5766::attributes::XorPeerAddress = 267 | track_assert_some!(indication.get_attribute(), ErrorKind::Other; indication); 268 | track_assert!( 269 | self.permissions.contains_key(&peer.address().ip()), 270 | ErrorKind::Other; peer, indication 271 | ); 272 | Ok(Some((peer.address(), Vec::from(data.data())))) 273 | } 274 | _ => { 275 | track_panic!(ErrorKind::Other; indication); 276 | } 277 | } 278 | } 279 | 280 | fn handle_channel_data(&mut self, data: ChannelData) -> Result<(SocketAddr, Vec)> { 281 | // FIXME: optimize 282 | let peer = track_assert_some!( 283 | self.channels 284 | .iter() 285 | .find(|x| x.1.channel_number() == data.channel_number()) 286 | .map(|x| *x.0), 287 | ErrorKind::Other 288 | ); 289 | Ok((peer, data.into_data())) 290 | } 291 | 292 | fn create_permission_inner(&mut self, peer: SocketAddr) -> Result<()> { 293 | // If a permission already exists on the TURN server, it will just be refreshed. 294 | let mut request = Request::new(rfc5766::methods::CREATE_PERMISSION); 295 | request.add_attribute(rfc5766::attributes::XorPeerAddress::new(peer).into()); 296 | track!(self.auth_params.add_auth_attributes(&mut request))?; 297 | 298 | self.create_permission_transaction = 299 | StunTransaction::with_peer(peer, self.stun_channel.call((), request)); 300 | Ok(()) 301 | } 302 | 303 | fn channel_bind_inner( 304 | &mut self, 305 | peer: SocketAddr, 306 | channel_number: ChannelNumber, 307 | ) -> Result<()> { 308 | track_assert!(!self.channels.contains_key(&peer), ErrorKind::InvalidInput; peer); 309 | 310 | let mut request = Request::new(rfc5766::methods::CHANNEL_BIND); 311 | request.add_attribute(rfc5766::attributes::XorPeerAddress::new(peer).into()); 312 | request.add_attribute(channel_number.into()); 313 | track!(self.auth_params.add_auth_attributes(&mut request))?; 314 | 315 | self.channel_bind_transaction = 316 | StunTransaction::with_peer(peer, self.stun_channel.call((), request)); 317 | Ok(()) 318 | } 319 | 320 | fn next_channel_number(&mut self) -> ChannelNumber { 321 | // FIXME: collision check 322 | let curr = self.next_channel_number; 323 | self.next_channel_number = curr.wrapping_increment(); 324 | curr 325 | } 326 | 327 | pub fn create_permission(&mut self, peer: SocketAddr) -> AsyncResult<()> { 328 | let (result, reply) = AsyncResult::new(); 329 | match track!(self.create_permission_inner(peer)) { 330 | Err(e) => { 331 | reply.send(Err(e)); 332 | } 333 | Ok(()) => { 334 | self.permissions.insert(peer.ip(), Some(reply)); 335 | } 336 | } 337 | result 338 | } 339 | 340 | pub fn channel_bind(&mut self, peer: SocketAddr) -> AsyncResult<()> { 341 | let (result, reply) = AsyncResult::new(); 342 | let channel_number = self.next_channel_number(); 343 | match track!(self.channel_bind_inner(peer, channel_number)) { 344 | Err(e) => { 345 | reply.send(Err(e)); 346 | } 347 | Ok(()) => { 348 | self.channels.insert( 349 | peer, 350 | ChannelState::Creating { 351 | number: channel_number, 352 | reply, 353 | }, 354 | ); 355 | } 356 | } 357 | result 358 | } 359 | 360 | pub fn start_send(&mut self, peer: SocketAddr, data: Vec) -> Result<()> { 361 | if let Some(state) = self.channels.get(&peer) { 362 | let data = track!(ChannelData::new(state.channel_number(), data,))?; 363 | track!(self.channel_data_transporter.start_send((), data))?; 364 | } else if self.permissions.contains_key(&peer.ip()) { 365 | track_assert!(self.permissions.contains_key(&peer.ip()), ErrorKind::Other; peer); 366 | let mut indication = Indication::new(rfc5766::methods::SEND); 367 | indication.add_attribute(rfc5766::attributes::XorPeerAddress::new(peer).into()); 368 | indication.add_attribute(track!(rfc5766::attributes::Data::new(data))?.into()); 369 | track!(self.stun_channel.cast((), indication))?; 370 | } else { 371 | track_panic!(ErrorKind::InvalidInput, "Unknown peer: {:?}", peer); 372 | } 373 | Ok(()) 374 | } 375 | 376 | pub fn poll_send(&mut self) -> Poll<(), Error> { 377 | let is_ready = track!(self.stun_channel.poll_send())?.is_ready() 378 | && track!(self.channel_data_transporter.poll_send())?.is_ready(); 379 | if is_ready { 380 | Ok(Async::Ready(())) 381 | } else { 382 | Ok(Async::NotReady) 383 | } 384 | } 385 | 386 | pub fn poll_recv(&mut self) -> Poll)>, Error> { 387 | let mut did_something = true; 388 | while did_something { 389 | did_something = false; 390 | 391 | while let Async::Ready(message) = track!(self.stun_channel.poll_recv())? { 392 | did_something = true; 393 | if let Some((_, message)) = message { 394 | if let Some((peer, data)) = track!(self.handle_stun_message(message))? { 395 | return Ok(Async::Ready(Some((peer, data)))); 396 | } 397 | } else { 398 | track_panic!(ErrorKind::Other, "Unexpected termination"); 399 | } 400 | } 401 | if let Async::Ready(data) = track!(self.channel_data_transporter.poll_recv())? { 402 | if let Some((_, data)) = data { 403 | let (peer, data) = track!(self.handle_channel_data(data))?; 404 | return Ok(Async::Ready(Some((peer, data)))); 405 | } else { 406 | track_panic!(ErrorKind::Other, "Unexpected termination"); 407 | } 408 | } 409 | while let Some(entry) = self.timeout_queue.pop() { 410 | did_something = true; 411 | track!(self.handle_timeout(entry))?; 412 | } 413 | if let Async::Ready(response) = track!(self.refresh_transaction.poll())? { 414 | did_something = true; 415 | track!(self.handle_refresh_response(response))?; 416 | } 417 | if let Async::Ready((peer, response)) = 418 | track!(self.create_permission_transaction.poll())? 419 | { 420 | did_something = true; 421 | track!(self.handle_create_permission_response(peer, response))?; 422 | } 423 | if let Async::Ready((peer, response)) = track!(self.channel_bind_transaction.poll())? { 424 | did_something = true; 425 | track!(self.handle_channel_bind_response(peer, response))?; 426 | } 427 | track!(self.channel_data_transporter.poll_send())?; 428 | } 429 | Ok(Async::NotReady) 430 | } 431 | } 432 | 433 | #[derive(Debug)] 434 | enum TimeoutEntry { 435 | Refresh, 436 | Permission { peer: SocketAddr }, 437 | Channel { peer: SocketAddr }, 438 | } 439 | 440 | #[derive(Debug)] 441 | enum ChannelState { 442 | Creating { 443 | number: ChannelNumber, 444 | reply: AsyncReply<()>, 445 | }, 446 | Created { 447 | number: ChannelNumber, 448 | }, 449 | } 450 | impl ChannelState { 451 | fn channel_number(&self) -> ChannelNumber { 452 | match self { 453 | ChannelState::Creating { number, .. } => *number, 454 | ChannelState::Created { number } => *number, 455 | } 456 | } 457 | } 458 | -------------------------------------------------------------------------------- /src/client/mod.rs: -------------------------------------------------------------------------------- 1 | use self::core::ClientCore; 2 | use crate::auth::AuthParams; 3 | use std::os::fd::AsRawFd; 4 | 5 | use crate::transport::{ 6 | ChannelDataTcpTransporter, ChannelDataUdpTransporter, StunTcpTransporter, StunTransporter, 7 | StunUdpTransporter, 8 | }; 9 | use crate::{AsyncResult, Error, ErrorKind, Result}; 10 | use fibers_transport::{ 11 | FixedPeerTransporter, RcTransporter, TcpTransport, TcpTransporter, UdpTransport, UdpTransporter, 12 | }; 13 | use futures::{Async, Future, Poll}; 14 | use std::net::SocketAddr; 15 | 16 | mod allocate; 17 | mod core; 18 | mod stun_transaction; 19 | 20 | pub trait Client { 21 | fn create_permission(&mut self, peer: SocketAddr) -> AsyncResult<()>; 22 | fn channel_bind(&mut self, peer: SocketAddr) -> AsyncResult<()>; 23 | fn start_send(&mut self, peer: SocketAddr, data: Vec) -> Result<()>; 24 | fn poll_send(&mut self) -> Poll<(), Error>; 25 | fn poll_recv(&mut self) -> Poll)>, Error>; 26 | fn local_addr(&self) -> SocketAddr; 27 | fn file_descriptor(&self) -> Option; 28 | } 29 | 30 | pub fn wait( 31 | mut client: C, 32 | f: FN, 33 | ) -> impl Future), Error = Error> 34 | where 35 | C: Client, 36 | FN: FnOnce(&mut C) -> FU, 37 | FU: Future, 38 | { 39 | let future = f(&mut client); 40 | Wait { 41 | client: Some(client), 42 | future, 43 | } 44 | } 45 | 46 | #[derive(Debug)] 47 | struct Wait { 48 | client: Option, 49 | future: F, 50 | } 51 | impl Future for Wait { 52 | type Item = (T, std::result::Result); 53 | type Error = Error; 54 | 55 | fn poll(&mut self) -> Poll { 56 | track!(self 57 | .client 58 | .as_mut() 59 | .expect("Cannot Wait poll twice") 60 | .poll_send())?; 61 | if let Async::Ready(item) = track!(self 62 | .client 63 | .as_mut() 64 | .expect("Cannot Wait poll twice") 65 | .poll_recv())? 66 | { 67 | track_panic!(ErrorKind::Other, "Unexpected reception: {:?}", item); 68 | } 69 | match self.future.poll() { 70 | Err(e) => Ok(Async::Ready(( 71 | self.client.take().expect("never fails"), 72 | Err(e), 73 | ))), 74 | Ok(Async::NotReady) => Ok(Async::NotReady), 75 | Ok(Async::Ready(v)) => Ok(Async::Ready(( 76 | self.client.take().expect("never fails"), 77 | Ok(v), 78 | ))), 79 | } 80 | } 81 | } 82 | 83 | #[derive(Debug)] 84 | pub struct TcpClient(ClientCore); 85 | impl TcpClient { 86 | pub fn allocate( 87 | server_addr: SocketAddr, 88 | auth_params: AuthParams, 89 | ) -> impl Future { 90 | TcpTransporter::connect(server_addr) 91 | .map_err(|e| track!(Error::from(e))) 92 | .and_then(move |transporter| { 93 | let transporter = RcTransporter::new(transporter); 94 | let stun = StunTcpTransporter::new(StunTransporter::new(transporter.clone())); 95 | let channel_data = ChannelDataTcpTransporter::new(transporter); 96 | track_err!(ClientCore::allocate(stun, channel_data, auth_params)) 97 | }) 98 | .map(TcpClient) 99 | } 100 | 101 | pub fn relay_addr(&self) -> Option { 102 | self.0.relay_addr() 103 | } 104 | } 105 | unsafe impl Send for TcpClient {} 106 | impl Client for TcpClient { 107 | fn create_permission(&mut self, peer: SocketAddr) -> AsyncResult<()> { 108 | self.0.create_permission(peer) 109 | } 110 | 111 | fn channel_bind(&mut self, peer: SocketAddr) -> AsyncResult<()> { 112 | self.0.channel_bind(peer) 113 | } 114 | 115 | fn start_send(&mut self, peer: SocketAddr, data: Vec) -> Result<()> { 116 | self.0.start_send(peer, data) 117 | } 118 | 119 | fn poll_send(&mut self) -> Poll<(), Error> { 120 | self.0.poll_send() 121 | } 122 | 123 | fn poll_recv(&mut self) -> Poll)>, Error> { 124 | self.0.poll_recv() 125 | } 126 | 127 | fn local_addr(&self) -> SocketAddr { 128 | self.0 129 | .stun_channel_ref() 130 | .transporter_ref() 131 | .inner_ref() 132 | .with_inner_ref(|x| x.local_addr()) 133 | } 134 | fn file_descriptor(&self) -> Option { 135 | None 136 | } 137 | } 138 | 139 | #[derive(Debug)] 140 | pub struct UdpClient( 141 | ClientCore< 142 | FixedPeerTransporter, 143 | FixedPeerTransporter, 144 | >, 145 | ); 146 | 147 | impl UdpClient { 148 | pub fn allocate( 149 | server_addr: SocketAddr, 150 | auth_params: AuthParams, 151 | ) -> impl Future { 152 | let bind_addr = "0.0.0.0:0".parse().expect("never fails"); 153 | UdpTransporter::bind(bind_addr) 154 | .map_err(|e| track!(Error::from(e))) 155 | .and_then(move |transporter| { 156 | let transporter = RcTransporter::new(transporter); 157 | let stun = StunUdpTransporter::new(StunTransporter::new(transporter.clone())); 158 | let stun = FixedPeerTransporter::new((), server_addr, stun); 159 | let channel_data = ChannelDataUdpTransporter::new(transporter); 160 | let channel_data = FixedPeerTransporter::new((), server_addr, channel_data); 161 | track_err!(ClientCore::allocate(stun, channel_data, auth_params)) 162 | }) 163 | .map(UdpClient) 164 | } 165 | 166 | pub fn relay_addr(&self) -> Option { 167 | self.0.relay_addr() 168 | } 169 | } 170 | unsafe impl Send for UdpClient {} 171 | impl Client for UdpClient { 172 | fn file_descriptor(&self) -> Option { 173 | let mut my_fd: Option = None; 174 | self.0 175 | .stun_channel_ref() 176 | .transporter_ref() 177 | .inner_ref() 178 | .inner_ref() 179 | .with_inner_ref(|f| { 180 | let socket: &fibers::net::UdpSocket = f.socket_ref(); 181 | socket.with_inner(|g| my_fd = Some(g.as_raw_fd())); 182 | }); 183 | my_fd 184 | } 185 | 186 | fn create_permission(&mut self, peer: SocketAddr) -> AsyncResult<()> { 187 | self.0.create_permission(peer) 188 | } 189 | 190 | fn channel_bind(&mut self, peer: SocketAddr) -> AsyncResult<()> { 191 | self.0.channel_bind(peer) 192 | } 193 | 194 | fn start_send(&mut self, peer: SocketAddr, data: Vec) -> Result<()> { 195 | self.0.start_send(peer, data) 196 | } 197 | 198 | fn poll_send(&mut self) -> Poll<(), Error> { 199 | self.0.poll_send() 200 | } 201 | 202 | fn poll_recv(&mut self) -> Poll)>, Error> { 203 | self.0.poll_recv() 204 | } 205 | 206 | fn local_addr(&self) -> SocketAddr { 207 | self.0 208 | .stun_channel_ref() 209 | .transporter_ref() 210 | .inner_ref() 211 | .inner_ref() 212 | .with_inner_ref(|x| x.local_addr()) 213 | } 214 | } 215 | -------------------------------------------------------------------------------- /src/client/stun_transaction.rs: -------------------------------------------------------------------------------- 1 | use crate::attribute::Attribute; 2 | use futures::{Future, Poll}; 3 | use rustun::message::{MessageError, Response}; 4 | use std::fmt; 5 | use std::net::SocketAddr; 6 | 7 | pub struct StunTransaction>( 8 | Box + Send + 'static>, 9 | ); 10 | impl StunTransaction> { 11 | pub fn new(future: F) -> Self 12 | where 13 | F: Future, Error = MessageError> + Send + 'static, 14 | { 15 | StunTransaction(Box::new(future.fuse())) 16 | } 17 | } 18 | impl StunTransaction<(SocketAddr, Response)> { 19 | pub fn with_peer(peer: SocketAddr, future: F) -> Self 20 | where 21 | F: Future, Error = MessageError> + Send + 'static, 22 | { 23 | StunTransaction(Box::new(future.map(move |item| (peer, item)).fuse())) 24 | } 25 | } 26 | impl StunTransaction 27 | where 28 | T: Send + 'static, 29 | { 30 | pub fn empty() -> Self { 31 | StunTransaction(Box::new(futures::empty())) 32 | } 33 | } 34 | impl Future for StunTransaction { 35 | type Item = T; 36 | type Error = MessageError; 37 | 38 | fn poll(&mut self) -> Poll { 39 | self.0.poll() 40 | } 41 | } 42 | impl fmt::Debug for StunTransaction { 43 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 44 | write!(f, "StunTransaction(_)") 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | //! A Rust implementation of [TURN][RFC 5766] server and client. 2 | //! 3 | //! # Examples 4 | //! 5 | //! ``` 6 | //! use futures::Future; 7 | //! use rustun::message::Request; 8 | //! use rustun::transport::StunUdpTransporter; 9 | //! use rusturn::auth::AuthParams; 10 | //! use rusturn::transport::UdpOverTurnTransporter; 11 | //! use stun_codec::{rfc5389, MessageDecoder, MessageEncoder}; 12 | //! 13 | //! # fn main() -> Result<(), trackable::error::MainError> { 14 | //! let client_auth_params = AuthParams::new("foo", "bar")?; 15 | //! let server_auth_params = 16 | //! AuthParams::with_realm_and_nonce("foo", "bar", "baz", "qux")?; 17 | //! 18 | //! // STUN server (peer) 19 | //! let stun_server = fibers_global::execute(rustun::server::UdpServer::start( 20 | //! fibers_global::handle(), 21 | //! "127.0.0.1:0".parse().unwrap(), 22 | //! rustun::server::BindingHandler, 23 | //! ))?; 24 | //! let stun_server_addr = stun_server.local_addr(); 25 | //! fibers_global::spawn(stun_server.map(|_| ()).map_err(|e| panic!("{}", e))); 26 | //! 27 | //! // TURN server 28 | //! let turn_server = fibers_global::execute(rusturn::server::UdpServer::start( 29 | //! "127.0.0.1:0".parse().unwrap(), 30 | //! server_auth_params, 31 | //! ))?; 32 | //! let turn_server_addr = turn_server.local_addr(); 33 | //! fibers_global::spawn(turn_server.map_err(|e| panic!("{}", e))); 34 | //! 35 | //! // TURN client 36 | //! let turn_client = fibers_global::execute(rusturn::client::UdpClient::allocate( 37 | //! turn_server_addr, 38 | //! client_auth_params 39 | //! ))?; 40 | //! let transporter = 41 | //! UdpOverTurnTransporter::<_, MessageEncoder<_>, MessageDecoder<_>>::new(turn_client); 42 | //! 43 | //! // STUN client (over TURN) 44 | //! let stun_channel = rustun::channel::Channel::new(StunUdpTransporter::new(transporter)); 45 | //! let stun_client = rustun::client::Client::new(&fibers_global::handle(), stun_channel); 46 | //! 47 | //! // BINDING request 48 | //! let request = Request::::new(rfc5389::methods::BINDING); 49 | //! let response = fibers_global::execute( 50 | //! stun_client.call(stun_server_addr, request) 51 | //! )?; 52 | //! assert!(response.is_ok(), "{:?}", response); 53 | //! # Ok(()) 54 | //! # } 55 | //! ``` 56 | //! 57 | //! # References 58 | //! 59 | //! - [RFC 5766: Traversal Using Relays around NAT (TURN)][RFC 5766] 60 | //! 61 | //! [RFC 5766]: https://tools.ietf.org/html/rfc5766 62 | #[macro_use] 63 | extern crate bytecodec; 64 | #[cfg(test)] 65 | extern crate fibers_global; 66 | #[macro_use] 67 | extern crate stun_codec; 68 | #[macro_use] 69 | extern crate trackable; 70 | 71 | pub use rustun::{Error, ErrorKind, Result}; 72 | 73 | pub mod attribute; 74 | 75 | pub mod auth; 76 | pub mod client; 77 | pub mod server; 78 | pub mod transport; 79 | 80 | mod channel_data; 81 | mod turn_message; 82 | 83 | #[derive(Debug)] 84 | pub struct AsyncResult(fibers::sync::oneshot::Monitor); 85 | impl AsyncResult { 86 | fn new() -> (Self, AsyncReply) { 87 | let (tx, rx) = fibers::sync::oneshot::monitor(); 88 | (AsyncResult(rx), AsyncReply(tx)) 89 | } 90 | } 91 | impl futures::Future for AsyncResult { 92 | type Item = T; 93 | type Error = Error; 94 | 95 | fn poll(&mut self) -> futures::Poll { 96 | track!(self.0.poll().map_err(Error::from)) 97 | } 98 | } 99 | 100 | #[derive(Debug)] 101 | struct AsyncReply(fibers::sync::oneshot::Monitored); 102 | impl AsyncReply { 103 | fn send(self, result: Result) { 104 | self.0.exit(result); 105 | } 106 | } 107 | 108 | #[cfg(test)] 109 | mod tests { 110 | use futures::Future; 111 | use rustun::message::Request; 112 | use rustun::transport::StunUdpTransporter; 113 | use stun_codec::rfc5389; 114 | use stun_codec::{MessageDecoder, MessageEncoder}; 115 | use trackable::error::MainError; 116 | 117 | use super::*; 118 | use auth::AuthParams; 119 | use transport::UdpOverTurnTransporter; 120 | 121 | #[test] 122 | fn it_works() -> std::result::Result<(), MainError> { 123 | let client_auth_params = track!(AuthParams::new("foo", "bar"))?; 124 | let server_auth_params = 125 | track!(AuthParams::with_realm_and_nonce("foo", "bar", "baz", "qux"))?; 126 | 127 | // STUN server (peer) 128 | let stun_server = fibers_global::execute(rustun::server::UdpServer::start( 129 | fibers_global::handle(), 130 | "127.0.0.1:0".parse().unwrap(), 131 | rustun::server::BindingHandler, 132 | ))?; 133 | let stun_server_addr = stun_server.local_addr(); 134 | fibers_global::spawn(stun_server.map(|_| ()).map_err(|e| panic!("{}", e))); 135 | 136 | // TURN server 137 | let turn_server = fibers_global::execute(server::UdpServer::start( 138 | "127.0.0.1:0".parse().unwrap(), 139 | server_auth_params, 140 | ))?; 141 | let turn_server_addr = turn_server.local_addr(); 142 | fibers_global::spawn(turn_server.map_err(|e| panic!("{}", e))); 143 | 144 | // TURN client 145 | let turn_client = track!(fibers_global::execute(client::UdpClient::allocate( 146 | turn_server_addr, 147 | client_auth_params 148 | )))?; 149 | let transporter = 150 | UdpOverTurnTransporter::<_, MessageEncoder<_>, MessageDecoder<_>>::new(turn_client); 151 | 152 | // STUN client (over TURN) 153 | let stun_channel = rustun::channel::Channel::new(StunUdpTransporter::new(transporter)); 154 | let stun_client = rustun::client::Client::new(&fibers_global::handle(), stun_channel); 155 | 156 | // BINDING request 157 | let request = Request::::new(rfc5389::methods::BINDING); 158 | let response = track!(fibers_global::execute( 159 | stun_client.call(stun_server_addr, request) 160 | ))?; 161 | assert!(response.is_ok(), "{:?}", response); 162 | 163 | Ok(()) 164 | } 165 | } 166 | -------------------------------------------------------------------------------- /src/server/core.rs: -------------------------------------------------------------------------------- 1 | use crate::attribute::Attribute; 2 | use crate::auth::AuthParams; 3 | use crate::channel_data::ChannelData; 4 | use crate::{Error, ErrorKind, Result}; 5 | use fibers_timeout_queue::TimeoutQueue; 6 | use fibers_transport::Transport; 7 | use futures::{Async, Future, Poll}; 8 | use rustun::channel::{Channel as StunChannel, RecvMessage}; 9 | use rustun::message::{ErrorResponse, Indication, Request, SuccessResponse}; 10 | use rustun::transport::StunTransport; 11 | use std::collections::HashMap; 12 | use std::net::UdpSocket as StdUdpSocket; 13 | use std::net::{IpAddr, SocketAddr}; 14 | use std::time::Duration; 15 | use stun_codec::rfc5766::attributes::ChannelNumber; 16 | use stun_codec::{rfc5389, rfc5766}; 17 | 18 | const ALLOCATION_LIEFTIME_SECONDS: u64 = 600; 19 | const PERMISSION_LIFETIME_SECONDS: u64 = 300; 20 | const CHANNEL_LIEFTIME_SECONDS: u64 = 600; 21 | 22 | #[derive(Debug)] 23 | pub struct ServerCore 24 | where 25 | S: StunTransport, 26 | C: Transport, 27 | { 28 | stun_channel: StunChannel, 29 | channel_data_transporter: C, 30 | allocations: HashMap, 31 | seqno: u64, 32 | auth_params: AuthParams, 33 | timeout_queue: TimeoutQueue, 34 | } 35 | impl ServerCore 36 | where 37 | S: StunTransport, 38 | C: Transport, 39 | { 40 | pub fn new(stun_transporter: S, channel_data_transporter: C, auth_params: AuthParams) -> Self { 41 | let mut timeout_queue = TimeoutQueue::new(); 42 | timeout_queue.push(TimeoutEntry::PollRecv, Duration::from_millis(100)); 43 | ServerCore { 44 | stun_channel: StunChannel::new(stun_transporter), 45 | channel_data_transporter, 46 | allocations: HashMap::new(), 47 | seqno: 0, 48 | auth_params, 49 | timeout_queue, 50 | } 51 | } 52 | 53 | pub fn stun_transporter_ref(&self) -> &S { 54 | self.stun_channel.transporter_ref() 55 | } 56 | 57 | fn handle_stun_message( 58 | &mut self, 59 | client: SocketAddr, 60 | message: RecvMessage, 61 | ) -> Result<()> { 62 | match message { 63 | RecvMessage::Request(m) => { 64 | track!(self.handle_stun_request(client, m))?; 65 | } 66 | RecvMessage::Indication(m) => { 67 | track!(self.handle_stun_indication(client, m))?; 68 | } 69 | RecvMessage::Invalid(m) => { 70 | #[allow(clippy::print_literal)] 71 | { 72 | eprintln!("[ERROR:{}:{}] Invalid message: {:?}", file!(), line!(), m); 73 | } 74 | } 75 | } 76 | Ok(()) 77 | } 78 | 79 | fn handle_stun_request( 80 | &mut self, 81 | client: SocketAddr, 82 | request: Request, 83 | ) -> Result<()> { 84 | match request.method() { 85 | rfc5766::methods::ALLOCATE => track!(self.handle_allocate(client, request))?, 86 | rfc5766::methods::REFRESH => track!(self.handle_refresh(client, request))?, 87 | rfc5766::methods::CREATE_PERMISSION => { 88 | track!(self.handle_create_permission(client, request))? 89 | } 90 | rfc5766::methods::CHANNEL_BIND => track!(self.handle_channel_bind(client, request))?, 91 | _ => track!(self.reply_bad_request(client, request))?, 92 | } 93 | Ok(()) 94 | } 95 | 96 | fn auth_validate(&self, request: &Request) -> Result<()> { 97 | let mi = track_assert_some!( 98 | request.get_attribute::(), 99 | ErrorKind::InvalidInput 100 | ); 101 | track!(self.auth_params.validate(mi))?; 102 | Ok(()) 103 | } 104 | 105 | fn handle_create_permission( 106 | &mut self, 107 | client: SocketAddr, 108 | request: Request, 109 | ) -> Result<()> { 110 | track!(self.auth_validate(&request))?; 111 | let peer = track_assert_some!( 112 | request.get_attribute::(), 113 | ErrorKind::InvalidInput 114 | ) 115 | .address(); 116 | 117 | let seqno = self.next_seqno(); 118 | let allocation = 119 | track_assert_some!(self.allocations.get_mut(&client), ErrorKind::InvalidInput); 120 | 121 | allocation 122 | .permissions 123 | .entry(peer.ip()) 124 | .or_insert_with(|| PermissionState { seqno }) 125 | .seqno = seqno; 126 | 127 | let mut response = SuccessResponse::new(&request); 128 | track!(self.auth_params.add_auth_attributes(&mut response))?; 129 | track!(self.stun_channel.reply(client, Ok(response)))?; 130 | 131 | self.timeout_queue.push( 132 | TimeoutEntry::Permission { 133 | client, 134 | peer: peer.ip(), 135 | seqno, 136 | }, 137 | Duration::from_secs(PERMISSION_LIFETIME_SECONDS), 138 | ); 139 | 140 | Ok(()) 141 | } 142 | 143 | fn handle_channel_bind( 144 | &mut self, 145 | client: SocketAddr, 146 | request: Request, 147 | ) -> Result<()> { 148 | track!(self.auth_validate(&request))?; 149 | let peer = track_assert_some!( 150 | request.get_attribute::(), 151 | ErrorKind::InvalidInput 152 | ) 153 | .address(); 154 | let channel_number = *track_assert_some!( 155 | request.get_attribute::(), 156 | ErrorKind::InvalidInput 157 | ); 158 | 159 | let seqno = self.next_seqno(); 160 | let allocation = 161 | track_assert_some!(self.allocations.get_mut(&client), ErrorKind::InvalidInput); 162 | 163 | allocation 164 | .channels 165 | .entry(channel_number) 166 | .or_insert_with(|| ChannelState::new(peer, seqno)) 167 | .seqno = seqno; 168 | 169 | let mut response = SuccessResponse::new(&request); 170 | track!(self.auth_params.add_auth_attributes(&mut response))?; 171 | track!(self.stun_channel.reply(client, Ok(response)))?; 172 | 173 | self.timeout_queue.push( 174 | TimeoutEntry::Channel { 175 | client, 176 | channel_number, 177 | seqno, 178 | }, 179 | Duration::from_secs(CHANNEL_LIEFTIME_SECONDS), 180 | ); 181 | 182 | Ok(()) 183 | } 184 | 185 | fn handle_refresh(&mut self, client: SocketAddr, request: Request) -> Result<()> { 186 | track!(self.auth_validate(&request))?; 187 | let lifetime = track_assert_some!( 188 | request.get_attribute::(), 189 | ErrorKind::InvalidInput 190 | ); 191 | if lifetime.lifetime().as_secs() == 0 { 192 | self.allocations.remove(&client); 193 | } else { 194 | let seqno = self.next_seqno(); 195 | let allocation = 196 | track_assert_some!(self.allocations.get_mut(&client), ErrorKind::InvalidInput); 197 | allocation.seqno = seqno; 198 | self.timeout_queue.push( 199 | TimeoutEntry::Allocation { client, seqno }, 200 | lifetime.lifetime(), 201 | ); 202 | 203 | let mut response = SuccessResponse::new(&request); 204 | response.add_attribute(lifetime.clone().into()); 205 | track!(self.auth_params.add_auth_attributes(&mut response))?; 206 | track!(self.stun_channel.reply(client, Ok(response)))?; 207 | } 208 | Ok(()) 209 | } 210 | 211 | fn handle_allocate(&mut self, client: SocketAddr, request: Request) -> Result<()> { 212 | if let Some(mi) = request.get_attribute::() { 213 | track!(self.auth_params.validate(mi))?; 214 | 215 | // FIXME: Add existence check 216 | let seqno = self.next_seqno(); 217 | let state = track!(AllocationState::new(seqno))?; 218 | let relay_addr = track!(state.socket.local_addr().map_err(Error::from))?; 219 | self.allocations.insert(client, state); 220 | 221 | let lifetime = Duration::from_secs(ALLOCATION_LIEFTIME_SECONDS); 222 | self.timeout_queue 223 | .push(TimeoutEntry::Allocation { client, seqno }, lifetime); 224 | 225 | let mut response = SuccessResponse::new(&request); 226 | response.add_attribute(track!(rfc5766::attributes::Lifetime::new(lifetime))?.into()); 227 | response.add_attribute(rfc5766::attributes::XorRelayAddress::new(relay_addr).into()); 228 | track!(self.auth_params.add_auth_attributes(&mut response))?; 229 | track!(self.stun_channel.reply(client, Ok(response)))?; 230 | } else { 231 | let realm = track_assert_some!(self.auth_params.get_realm(), ErrorKind::InvalidInput); 232 | let nonce = track_assert_some!(self.auth_params.get_nonce(), ErrorKind::InvalidInput); 233 | 234 | let mut response = ErrorResponse::new(&request, rfc5389::errors::Unauthorized.into()); 235 | response.add_attribute(realm.clone().into()); 236 | response.add_attribute(nonce.clone().into()); 237 | track!(self.stun_channel.reply(client, Err(response)))?; 238 | } 239 | Ok(()) 240 | } 241 | 242 | fn handle_stun_indication( 243 | &mut self, 244 | client: SocketAddr, 245 | indication: Indication, 246 | ) -> Result<()> { 247 | match indication.method() { 248 | rfc5766::methods::SEND => { 249 | track!(self.handle_send(client, indication))?; 250 | } 251 | _ => { 252 | #[allow(clippy::print_literal)] 253 | { 254 | eprintln!( 255 | "[WARN:{}:{}] Unknown STUN indication: {:?}", 256 | file!(), 257 | line!(), 258 | indication 259 | ); 260 | } 261 | } 262 | } 263 | Ok(()) 264 | } 265 | 266 | fn handle_send(&mut self, client: SocketAddr, indication: Indication) -> Result<()> { 267 | let allocation = 268 | track_assert_some!(self.allocations.get_mut(&client), ErrorKind::InvalidInput); 269 | let peer = track_assert_some!( 270 | indication.get_attribute::(), 271 | ErrorKind::InvalidInput 272 | ) 273 | .address(); 274 | let data = track_assert_some!( 275 | indication.get_attribute::(), 276 | ErrorKind::InvalidInput 277 | ); 278 | track_assert!( 279 | allocation.permissions.contains_key(&peer.ip()), 280 | ErrorKind::InvalidInput 281 | ); 282 | track!(allocation 283 | .socket 284 | .send_to(data.data(), peer) 285 | .map_err(Error::from))?; 286 | 287 | Ok(()) 288 | } 289 | 290 | fn reply_bad_request(&mut self, client: SocketAddr, request: Request) -> Result<()> { 291 | let response = ErrorResponse::new(&request, rfc5389::errors::BadRequest.into()); 292 | track!(self.stun_channel.reply(client, Err(response)))?; 293 | Ok(()) 294 | } 295 | 296 | fn handle_channel_data(&mut self, client: SocketAddr, data: ChannelData) -> Result<()> { 297 | let allocation = 298 | track_assert_some!(self.allocations.get_mut(&client), ErrorKind::InvalidInput); 299 | let channel = track_assert_some!( 300 | allocation.channels.get_mut(&data.channel_number()), 301 | ErrorKind::InvalidInput 302 | ); 303 | track!(allocation 304 | .socket 305 | .send_to(&data.into_data(), channel.peer_addr) 306 | .map_err(Error::from))?; 307 | Ok(()) 308 | } 309 | 310 | fn next_seqno(&mut self) -> u64 { 311 | let n = self.seqno; 312 | self.seqno += 1; 313 | n 314 | } 315 | 316 | fn handle_timeout(&mut self, entry: TimeoutEntry) -> Result<()> { 317 | match entry { 318 | TimeoutEntry::Allocation { client, seqno } => { 319 | let do_delete = self 320 | .allocations 321 | .get(&client) 322 | .map_or(false, |s| s.seqno == seqno); 323 | if do_delete { 324 | self.allocations.remove(&client); 325 | } 326 | } 327 | TimeoutEntry::Permission { 328 | client, 329 | peer, 330 | seqno, 331 | } => { 332 | if let Some(allocation) = self.allocations.get_mut(&client) { 333 | let do_delete = allocation 334 | .permissions 335 | .get_mut(&peer) 336 | .map_or(false, |s| s.seqno == seqno); 337 | if do_delete { 338 | allocation.permissions.remove(&peer); 339 | } 340 | } 341 | } 342 | TimeoutEntry::Channel { 343 | client, 344 | channel_number, 345 | seqno, 346 | } => { 347 | // FIXME: Check permission lifetime 348 | if let Some(allocation) = self.allocations.get_mut(&client) { 349 | let do_delete = allocation 350 | .channels 351 | .get_mut(&channel_number) 352 | .map_or(false, |s| s.seqno == seqno); 353 | if do_delete { 354 | allocation.channels.remove(&channel_number); 355 | } 356 | } 357 | } 358 | TimeoutEntry::PollRecv => { 359 | // FIXME: Use asynchronous UDP socket 360 | track!(self.poll_peer_recv())?; 361 | self.timeout_queue 362 | .push(TimeoutEntry::PollRecv, Duration::from_millis(100)); 363 | } 364 | } 365 | Ok(()) 366 | } 367 | 368 | fn poll_peer_recv(&mut self) -> Result<()> { 369 | let mut buf = [0; 4096]; 370 | for (client, allocation) in &mut self.allocations { 371 | match allocation.socket.recv_from(&mut buf) { 372 | Err(e) => { 373 | use std::io; 374 | track_assert!( 375 | e.kind() == io::ErrorKind::WouldBlock, 376 | ErrorKind::Other, 377 | "I/O Error: {}", 378 | e 379 | ); 380 | } 381 | Ok((size, peer)) => { 382 | let data = Vec::from(&buf[..size]); 383 | 384 | // FIXME: optimize 385 | if let Some(&channel_number) = allocation 386 | .channels 387 | .iter() 388 | .find(|(_, s)| s.peer_addr == peer) 389 | .map(|x| x.0) 390 | { 391 | let data = track!(ChannelData::new(channel_number, data))?; 392 | track!(self.channel_data_transporter.start_send(*client, data))?; 393 | } else { 394 | track_assert!( 395 | allocation.permissions.contains_key(&peer.ip()), 396 | ErrorKind::InvalidInput 397 | ); 398 | 399 | let mut indication = Indication::new(rfc5766::methods::DATA); 400 | indication 401 | .add_attribute(rfc5766::attributes::XorPeerAddress::new(peer).into()); 402 | indication 403 | .add_attribute(track!(rfc5766::attributes::Data::new(data))?.into()); 404 | track!(self.stun_channel.cast(*client, indication))?; 405 | } 406 | } 407 | } 408 | } 409 | Ok(()) 410 | } 411 | } 412 | unsafe impl Send for ServerCore 413 | where 414 | S: StunTransport, 415 | C: Transport, 416 | { 417 | } 418 | impl Future for ServerCore 419 | where 420 | S: StunTransport, 421 | C: Transport, 422 | { 423 | type Item = (); 424 | type Error = Error; 425 | 426 | fn poll(&mut self) -> Poll { 427 | let mut did_something = true; 428 | while did_something { 429 | did_something = false; 430 | 431 | while let Async::Ready(message) = track!(self.stun_channel.poll_recv())? { 432 | did_something = true; 433 | if let Some((client, message)) = message { 434 | track!(self.handle_stun_message(client, message))?; 435 | } else { 436 | return Ok(Async::Ready(())); 437 | } 438 | } 439 | while let Async::Ready(data) = track!(self.channel_data_transporter.poll_recv())? { 440 | did_something = true; 441 | if let Some((client, data)) = data { 442 | track!(self.handle_channel_data(client, data))?; 443 | } else { 444 | return Ok(Async::Ready(())); 445 | } 446 | } 447 | track!(self.stun_channel.poll_send())?; 448 | track!(self.channel_data_transporter.poll_send())?; 449 | while let Some(entry) = self.timeout_queue.pop() { 450 | did_something = true; 451 | track!(self.handle_timeout(entry))?; 452 | } 453 | } 454 | Ok(Async::NotReady) 455 | } 456 | } 457 | 458 | #[derive(Debug)] 459 | struct AllocationState { 460 | seqno: u64, 461 | socket: StdUdpSocket, 462 | permissions: HashMap, 463 | channels: HashMap, 464 | } 465 | impl AllocationState { 466 | fn new(seqno: u64) -> Result { 467 | // FIXME: Make asynchronous 468 | let socket = track!(StdUdpSocket::bind("0.0.0.0:0").map_err(Error::from))?; 469 | track!(socket.set_nonblocking(true).map_err(Error::from))?; 470 | Ok(AllocationState { 471 | seqno, 472 | socket, 473 | permissions: HashMap::new(), 474 | channels: HashMap::new(), 475 | }) 476 | } 477 | } 478 | 479 | #[derive(Debug)] 480 | struct ChannelState { 481 | peer_addr: SocketAddr, 482 | seqno: u64, 483 | } 484 | impl ChannelState { 485 | fn new(peer_addr: SocketAddr, seqno: u64) -> Self { 486 | ChannelState { peer_addr, seqno } 487 | } 488 | } 489 | 490 | #[derive(Debug)] 491 | struct PermissionState { 492 | seqno: u64, 493 | } 494 | 495 | #[derive(Debug)] 496 | enum TimeoutEntry { 497 | Allocation { 498 | client: SocketAddr, 499 | seqno: u64, 500 | }, 501 | Permission { 502 | client: SocketAddr, 503 | peer: IpAddr, 504 | seqno: u64, 505 | }, 506 | Channel { 507 | client: SocketAddr, 508 | channel_number: ChannelNumber, 509 | seqno: u64, 510 | }, 511 | PollRecv, 512 | } 513 | -------------------------------------------------------------------------------- /src/server/mod.rs: -------------------------------------------------------------------------------- 1 | use self::core::ServerCore; 2 | use crate::auth::AuthParams; 3 | use crate::transport::{ 4 | ChannelDataTcpTransporter, ChannelDataUdpTransporter, StunTcpTransporter, StunTransporter, 5 | StunUdpTransporter, 6 | }; 7 | use crate::turn_message::{TurnMessageDecoder, TurnMessageEncoder}; 8 | use crate::Error; 9 | use factory::DefaultFactory; 10 | use fibers::{BoxSpawn, Spawn}; 11 | use fibers_transport::{ 12 | FixedPeerTransporter, RcTransporter, TcpListener, TcpTransport, UdpTransport, UdpTransporter, 13 | }; 14 | use futures::{Async, Future, Poll, Stream}; 15 | use std::net::SocketAddr; 16 | 17 | mod core; 18 | 19 | #[derive(Debug)] 20 | #[must_use = "future do nothing unless polled"] 21 | pub struct UdpServer { 22 | core: ServerCore, 23 | } 24 | impl UdpServer { 25 | pub fn start( 26 | bind_addr: SocketAddr, 27 | auth_params: AuthParams, 28 | ) -> impl Future { 29 | UdpTransporter::bind(bind_addr) 30 | .map_err(|e| track!(Error::from(e))) 31 | .map(move |transporter| { 32 | let transporter = RcTransporter::new(transporter); 33 | let stun = StunUdpTransporter::new(StunTransporter::new(transporter.clone())); 34 | let channel_data = ChannelDataUdpTransporter::new(transporter); 35 | let core = ServerCore::new(stun, channel_data, auth_params); 36 | UdpServer { core } 37 | }) 38 | } 39 | 40 | pub fn local_addr(&self) -> SocketAddr { 41 | self.core 42 | .stun_transporter_ref() 43 | .inner_ref() 44 | .with_inner_ref(|x| x.local_addr()) 45 | } 46 | } 47 | impl Future for UdpServer { 48 | type Item = (); 49 | type Error = Error; 50 | 51 | fn poll(&mut self) -> Poll { 52 | match track!(self.core.poll()) { 53 | Err(e) => { 54 | log::warn!("{}", e); 55 | Ok(Async::NotReady) 56 | } 57 | other => other, 58 | } 59 | } 60 | } 61 | 62 | #[derive(Debug)] 63 | #[must_use = "future do nothing unless polled"] 64 | pub struct TcpServer { 65 | listener: TcpListener, DefaultFactory>, 66 | spawner: BoxSpawn, 67 | auth_params: AuthParams, 68 | } 69 | impl TcpServer { 70 | pub fn start( 71 | spawner: S, 72 | bind_addr: SocketAddr, 73 | auth_params: AuthParams, 74 | ) -> impl Future 75 | where 76 | S: Spawn + Send + 'static, 77 | { 78 | TcpListener::listen(bind_addr) 79 | .map_err(|e| track!(Error::from(e))) 80 | .map(move |listener| TcpServer { 81 | listener, 82 | spawner: spawner.boxed(), 83 | auth_params, 84 | }) 85 | } 86 | 87 | pub fn local_addr(&self) -> SocketAddr { 88 | self.listener.local_addr() 89 | } 90 | } 91 | impl Future for TcpServer { 92 | type Item = (); 93 | type Error = Error; 94 | 95 | fn poll(&mut self) -> Poll { 96 | while let Async::Ready(transporter) = track!(self.listener.poll())? { 97 | if let Some(transporter) = transporter { 98 | let peer = transporter.peer_addr(); 99 | let transporter = RcTransporter::new(transporter); 100 | let stun = StunTcpTransporter::new(StunTransporter::new(transporter.clone())); 101 | let stun = FixedPeerTransporter::new(peer, (), stun); 102 | let channel_data = ChannelDataTcpTransporter::new(transporter); 103 | let channel_data = FixedPeerTransporter::new(peer, (), channel_data); 104 | let auth_params = self.auth_params.clone(); 105 | self.spawner.spawn( 106 | ServerCore::new(stun, channel_data, auth_params).map_err(|e| panic!("{}", e)), 107 | ); 108 | } else { 109 | return Ok(Async::Ready(())); 110 | } 111 | } 112 | Ok(Async::NotReady) 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /src/transport/channel_data.rs: -------------------------------------------------------------------------------- 1 | use crate::channel_data::ChannelData; 2 | use crate::turn_message::TurnMessage; 3 | use fibers_transport::{PollRecv, PollSend, RcTransporter, Result, Transport}; 4 | use futures::Async; 5 | 6 | #[derive(Debug)] 7 | pub struct ChannelDataTransporter { 8 | inner: RcTransporter, 9 | } 10 | impl ChannelDataTransporter 11 | where 12 | T: Transport, 13 | { 14 | pub fn new(inner: RcTransporter) -> Self { 15 | ChannelDataTransporter { inner } 16 | } 17 | } 18 | impl Transport for ChannelDataTransporter 19 | where 20 | T: Transport, 21 | { 22 | type PeerAddr = T::PeerAddr; 23 | type SendItem = ChannelData; 24 | type RecvItem = ChannelData; 25 | 26 | fn start_send(&mut self, peer: Self::PeerAddr, item: Self::SendItem) -> Result<()> { 27 | track!(self.inner.start_send(peer, TurnMessage::ChannelData(item))) 28 | } 29 | 30 | fn poll_send(&mut self) -> PollSend { 31 | track!(self.inner.poll_send()) 32 | } 33 | 34 | fn poll_recv(&mut self) -> PollRecv<(Self::PeerAddr, Self::RecvItem)> { 35 | let do_recv = track!(self 36 | .inner 37 | .with_peek_recv(|_peer, item| { matches!(item, TurnMessage::ChannelData(_)) }))?; 38 | if do_recv == Some(true) { 39 | match track!(self.inner.poll_recv())? { 40 | Async::Ready(Some((peer, TurnMessage::ChannelData(item)))) => { 41 | Ok(Async::Ready(Some((peer, item)))) 42 | } 43 | Async::Ready(Some(_)) => unreachable!(), 44 | Async::Ready(None) => Ok(Async::Ready(None)), 45 | Async::NotReady => Ok(Async::NotReady), 46 | } 47 | } else { 48 | Ok(Async::NotReady) 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/transport/mod.rs: -------------------------------------------------------------------------------- 1 | use crate::attribute::Attribute; 2 | use crate::turn_message::{TurnMessageDecoder, TurnMessageEncoder}; 3 | use fibers_transport::{TcpTransporter, UdpTransporter}; 4 | 5 | pub(crate) use self::channel_data::ChannelDataTransporter; 6 | pub(crate) use self::stun::StunTransporter; 7 | 8 | pub use self::udp_over_turn::UdpOverTurnTransporter; 9 | 10 | mod channel_data; 11 | mod stun; 12 | mod udp_over_turn; 13 | 14 | pub(crate) type StunTcpTransporter = 15 | rustun::transport::StunTcpTransporter>; 16 | 17 | pub(crate) type StunUdpTransporter = 18 | rustun::transport::StunUdpTransporter>; 19 | 20 | pub(crate) type ChannelDataTcpTransporter = ChannelDataTransporter; 21 | 22 | pub(crate) type ChannelDataUdpTransporter = ChannelDataTransporter; 23 | 24 | pub(crate) type TurnUdpTransporter = UdpTransporter; 25 | 26 | pub(crate) type TurnTcpTransporter = TcpTransporter; 27 | -------------------------------------------------------------------------------- /src/transport/stun.rs: -------------------------------------------------------------------------------- 1 | use crate::attribute::Attribute; 2 | use crate::turn_message::TurnMessage; 3 | use fibers_transport::{ 4 | PollRecv, PollSend, RcTransporter, Result, TcpTransport, Transport, UdpTransport, 5 | }; 6 | use futures::Async; 7 | use std::net::SocketAddr; 8 | use stun_codec::{DecodedMessage, Message}; 9 | 10 | #[derive(Debug)] 11 | pub struct StunTransporter { 12 | inner: RcTransporter, 13 | } 14 | impl StunTransporter 15 | where 16 | T: Transport, 17 | { 18 | pub fn new(inner: RcTransporter) -> Self { 19 | StunTransporter { inner } 20 | } 21 | 22 | pub fn with_inner_ref(&self, f: F) -> U 23 | where 24 | F: FnOnce(&T) -> U, 25 | { 26 | self.inner.with_inner_ref(f) 27 | } 28 | } 29 | impl Transport for StunTransporter 30 | where 31 | T: Transport, 32 | { 33 | type PeerAddr = T::PeerAddr; 34 | type SendItem = Message; 35 | type RecvItem = DecodedMessage; 36 | 37 | fn start_send(&mut self, peer: Self::PeerAddr, item: Self::SendItem) -> Result<()> { 38 | track!(self.inner.start_send(peer, TurnMessage::Stun(item))) 39 | } 40 | 41 | fn poll_send(&mut self) -> PollSend { 42 | track!(self.inner.poll_send()) 43 | } 44 | 45 | fn poll_recv(&mut self) -> PollRecv<(Self::PeerAddr, Self::RecvItem)> { 46 | let do_recv = track!(self 47 | .inner 48 | .with_peek_recv(|_peer, item| { !matches!(item, TurnMessage::ChannelData(_)) }))?; 49 | if do_recv == Some(true) { 50 | match track!(self.inner.poll_recv())? { 51 | Async::Ready(Some((peer, TurnMessage::Stun(item)))) => { 52 | Ok(Async::Ready(Some((peer, Ok(item))))) 53 | } 54 | Async::Ready(Some((peer, TurnMessage::BrokenStun(item)))) => { 55 | Ok(Async::Ready(Some((peer, Err(item))))) 56 | } 57 | Async::Ready(Some(_)) => unreachable!(), 58 | Async::Ready(None) => Ok(Async::Ready(None)), 59 | Async::NotReady => Ok(Async::NotReady), 60 | } 61 | } else { 62 | Ok(Async::NotReady) 63 | } 64 | } 65 | } 66 | impl TcpTransport for StunTransporter 67 | where 68 | T: TcpTransport, 69 | { 70 | fn peer_addr(&self) -> SocketAddr { 71 | self.inner.with_inner_ref(|x| x.peer_addr()) 72 | } 73 | 74 | fn local_addr(&self) -> SocketAddr { 75 | self.inner.with_inner_ref(|x| x.local_addr()) 76 | } 77 | } 78 | impl UdpTransport for StunTransporter 79 | where 80 | T: UdpTransport, 81 | { 82 | fn local_addr(&self) -> SocketAddr { 83 | self.inner.with_inner_ref(|x| x.local_addr()) 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/transport/udp_over_turn.rs: -------------------------------------------------------------------------------- 1 | use crate::client::Client; 2 | use bytecodec::{Decode, DecodeExt, Encode, EncodeExt}; 3 | use fibers_transport::{ErrorKind, PollRecv, PollSend, Result, Transport, UdpTransport}; 4 | use futures::Async; 5 | use std::collections::HashSet; 6 | use std::net::SocketAddr; 7 | use trackable::error::ErrorKindExt; 8 | 9 | #[derive(Debug)] 10 | pub struct UdpOverTurnTransporter { 11 | client: C, 12 | encoder: E, 13 | decoder: D, 14 | channels: HashSet, 15 | } 16 | impl UdpOverTurnTransporter 17 | where 18 | C: Client, 19 | E: Encode + Default, 20 | D: Decode + Default, 21 | { 22 | pub fn new(client: C) -> Self { 23 | UdpOverTurnTransporter { 24 | client, 25 | encoder: E::default(), 26 | decoder: D::default(), 27 | channels: HashSet::new(), 28 | } 29 | } 30 | 31 | fn ensure_channel_exists(&mut self, peer: SocketAddr) { 32 | if self.channels.insert(peer) { 33 | self.client.channel_bind(peer); 34 | } 35 | } 36 | } 37 | impl Transport for UdpOverTurnTransporter 38 | where 39 | C: Client, 40 | E: Encode + Default, 41 | D: Decode + Default, 42 | { 43 | type PeerAddr = SocketAddr; 44 | type SendItem = E::Item; 45 | type RecvItem = D::Item; 46 | 47 | fn start_send(&mut self, peer: SocketAddr, message: Self::SendItem) -> Result<()> { 48 | self.ensure_channel_exists(peer); 49 | let data = track!(self.encoder.encode_into_bytes(message))?; 50 | track!(self 51 | .client 52 | .start_send(peer, data) 53 | .map_err(|e| ErrorKind::Other.takes_over(e)))?; 54 | Ok(()) 55 | } 56 | 57 | fn poll_send(&mut self) -> PollSend { 58 | track!(self 59 | .client 60 | .poll_send() 61 | .map_err(|e| ErrorKind::Other.takes_over(e).into())) 62 | } 63 | 64 | fn poll_recv(&mut self) -> PollRecv<(SocketAddr, Self::RecvItem)> { 65 | let result = track!(self 66 | .client 67 | .poll_recv() 68 | .map_err(|e| ErrorKind::Other.takes_over(e)))?; 69 | if let Async::Ready(Some((peer, data))) = result { 70 | let item = track!(self.decoder.decode_from_bytes(&data))?; 71 | Ok(Async::Ready(Some((peer, item)))) 72 | } else { 73 | Ok(Async::NotReady) 74 | } 75 | } 76 | } 77 | impl UdpTransport for UdpOverTurnTransporter 78 | where 79 | C: Client, 80 | E: Encode + Default, 81 | D: Decode + Default, 82 | { 83 | fn local_addr(&self) -> SocketAddr { 84 | self.client.local_addr() 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /src/turn_message.rs: -------------------------------------------------------------------------------- 1 | use crate::attribute::Attribute; 2 | use crate::channel_data::{ChannelData, ChannelDataDecoder, ChannelDataEncoder}; 3 | use bytecodec::{ByteCount, Decode, Encode, EncodeExt, Eos, ErrorKind, Result, SizedEncode}; 4 | use stun_codec as stun; 5 | 6 | #[derive(Debug)] 7 | pub enum TurnMessage { 8 | Stun(stun::Message), 9 | BrokenStun(stun::BrokenMessage), 10 | ChannelData(ChannelData), 11 | } 12 | 13 | #[derive(Debug, Default)] 14 | #[allow(clippy::large_enum_variant)] 15 | pub enum TurnMessageDecoder { 16 | Stun(stun::MessageDecoder), 17 | ChannelData(ChannelDataDecoder), 18 | #[default] 19 | None, 20 | } 21 | 22 | impl Decode for TurnMessageDecoder { 23 | type Item = TurnMessage; 24 | 25 | fn decode(&mut self, buf: &[u8], eos: Eos) -> Result { 26 | loop { 27 | let next = match self { 28 | TurnMessageDecoder::Stun(x) => { 29 | let result = track!(x.decode(buf, eos)); 30 | if result.is_err() { 31 | *self = TurnMessageDecoder::None; 32 | } 33 | return result; 34 | } 35 | TurnMessageDecoder::ChannelData(x) => { 36 | let result = track!(x.decode(buf, eos)); 37 | if result.is_err() { 38 | *self = TurnMessageDecoder::None; 39 | } 40 | return result; 41 | } 42 | TurnMessageDecoder::None => match buf.first().map(|&b| b >> 6) { 43 | None => return Ok(0), 44 | Some(0b00) => TurnMessageDecoder::Stun(Default::default()), 45 | Some(0b01) => TurnMessageDecoder::ChannelData(Default::default()), 46 | Some(prefix) => { 47 | track_panic!( 48 | ErrorKind::InvalidInput, 49 | "Unknown codec: prefix=0b{:b}", 50 | prefix 51 | ); 52 | } 53 | }, 54 | }; 55 | *self = next; 56 | } 57 | } 58 | 59 | fn finish_decoding(&mut self) -> Result { 60 | let item = match self { 61 | TurnMessageDecoder::Stun(x) => track!(x.finish_decoding()).map(|x| { 62 | x.map(TurnMessage::Stun) 63 | .unwrap_or_else(TurnMessage::BrokenStun) 64 | })?, 65 | TurnMessageDecoder::ChannelData(x) => { 66 | track!(x.finish_decoding().map(TurnMessage::ChannelData))? 67 | } 68 | TurnMessageDecoder::None => track_panic!(ErrorKind::IncompleteDecoding), 69 | }; 70 | *self = TurnMessageDecoder::None; 71 | Ok(item) 72 | } 73 | 74 | fn requiring_bytes(&self) -> ByteCount { 75 | match self { 76 | TurnMessageDecoder::Stun(x) => x.requiring_bytes(), 77 | TurnMessageDecoder::ChannelData(x) => x.requiring_bytes(), 78 | TurnMessageDecoder::None => ByteCount::Finite(0), 79 | } 80 | } 81 | } 82 | 83 | #[derive(Debug, Default)] 84 | #[allow(clippy::large_enum_variant)] 85 | pub enum TurnMessageEncoder { 86 | Stun(stun::MessageEncoder), 87 | ChannelData(ChannelDataEncoder), 88 | #[default] 89 | None, 90 | } 91 | impl Encode for TurnMessageEncoder { 92 | type Item = TurnMessage; 93 | 94 | fn encode(&mut self, buf: &mut [u8], eos: Eos) -> Result { 95 | match self { 96 | TurnMessageEncoder::Stun(x) => track!(x.encode(buf, eos)), 97 | TurnMessageEncoder::ChannelData(x) => track!(x.encode(buf, eos)), 98 | TurnMessageEncoder::None => Ok(0), 99 | } 100 | } 101 | 102 | fn start_encoding(&mut self, item: Self::Item) -> Result<()> { 103 | track_assert!(self.is_idle(), ErrorKind::EncoderFull); 104 | *self = match item { 105 | TurnMessage::Stun(t) => track!(EncodeExt::with_item(t).map(TurnMessageEncoder::Stun))?, 106 | TurnMessage::BrokenStun(t) => { 107 | track_panic!(ErrorKind::InvalidInput, "{:?}", t); 108 | } 109 | TurnMessage::ChannelData(t) => { 110 | track!(EncodeExt::with_item(t).map(TurnMessageEncoder::ChannelData))? 111 | } 112 | }; 113 | Ok(()) 114 | } 115 | 116 | fn requiring_bytes(&self) -> ByteCount { 117 | ByteCount::Finite(self.exact_requiring_bytes()) 118 | } 119 | } 120 | impl SizedEncode for TurnMessageEncoder { 121 | fn exact_requiring_bytes(&self) -> u64 { 122 | match self { 123 | TurnMessageEncoder::Stun(x) => x.exact_requiring_bytes(), 124 | TurnMessageEncoder::ChannelData(x) => x.exact_requiring_bytes(), 125 | TurnMessageEncoder::None => 0, 126 | } 127 | } 128 | } 129 | --------------------------------------------------------------------------------