├── tests ├── certs │ ├── ca.srl │ ├── ca2.srl │ ├── device.invalid.crt │ ├── device.test.crt │ ├── ca2.crt │ ├── ca.crt │ ├── ca.key │ ├── ca2.key │ └── device.key └── integration.rs ├── picoquic-sys ├── src │ ├── lib.rs │ └── picoquic.rs ├── Cargo.toml └── build.rs ├── Dockerfile ├── .gitmodules ├── .gitignore ├── .travis.yml ├── src ├── ffi │ ├── mod.rs │ ├── stateless_packet.rs │ ├── verify_certificate.rs │ ├── connection.rs │ └── quic_ctx.rs ├── verify_certificate.rs ├── swappable_stream.rs ├── context.rs ├── error.rs ├── channel_with_error.rs ├── lib.rs ├── config.rs ├── context_inner.rs ├── stream.rs └── connection.rs ├── Cargo.toml ├── examples ├── client.rs ├── cert.pem ├── ca_cert.pem ├── key.pem └── server.rs └── README.md /tests/certs/ca.srl: -------------------------------------------------------------------------------- 1 | 8325BBB7BF3E3FFC 2 | -------------------------------------------------------------------------------- /tests/certs/ca2.srl: -------------------------------------------------------------------------------- 1 | 98B105E5E205A7BD 2 | -------------------------------------------------------------------------------- /picoquic-sys/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![recursion_limit = "1024"] 2 | 3 | pub mod picoquic; 4 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM rust:latest 2 | 3 | RUN apt-get update && apt-get -y install openssl libclang-dev clang 4 | -------------------------------------------------------------------------------- /picoquic-sys/src/picoquic.rs: -------------------------------------------------------------------------------- 1 | // Disable the warnings for our bindings 2 | #![allow(non_upper_case_globals)] 3 | #![allow(non_camel_case_types)] 4 | #![allow(non_snake_case)] 5 | 6 | include!(concat!(env!("OUT_DIR"), "/picoquic.rs")); 7 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "picoquic-sys/src/picoquic"] 2 | path = picoquic-sys/src/picoquic 3 | url = https://github.com/bkchr/picoquic.git 4 | [submodule "picoquic-sys/src/picotls"] 5 | path = picoquic-sys/src/picotls 6 | url = https://github.com/bkchr/picotls.git 7 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Generated by Cargo 2 | # will have compiled files and executables 3 | /target/ 4 | /picoquic-sys/target/ 5 | 6 | # Remove Cargo.lock from gitignore if creating an executable, leave it for libraries 7 | # More information here http://doc.crates.io/guide.html#cargotoml-vs-cargolock 8 | Cargo.lock 9 | 10 | # These are backup files generated by rustfmt 11 | **/*.rs.bk 12 | 13 | default.nix 14 | .envrc 15 | .direnv 16 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: required 2 | 3 | language: rust 4 | 5 | services: 6 | - docker 7 | 8 | git: 9 | submodules: false 10 | 11 | before_install: 12 | - sed -i 's/git@github.com:/https:\/\/github.com\//' .gitmodules 13 | - git submodule update --init --recursive 14 | - cat Dockerfile | docker build -t picoquic-rs - 15 | 16 | script: 17 | # We need to use 1 thread for the tests, because the calls to OpenSSL are not guarded. 18 | - docker run --rm --user "$(id -u)":"$(id -g)" -v "$PWD":/src -w /src picoquic-rs cargo test --all -- --test-threads=1 19 | -------------------------------------------------------------------------------- /src/ffi/mod.rs: -------------------------------------------------------------------------------- 1 | use std::ops::Deref; 2 | 3 | mod connection; 4 | mod quic_ctx; 5 | mod stateless_packet; 6 | mod verify_certificate; 7 | 8 | pub use self::connection::Connection; 9 | pub use self::quic_ctx::MicroSeconds; 10 | pub use self::quic_ctx::QuicCtx; 11 | 12 | #[derive(Copy, Clone)] 13 | pub struct Pointer(*mut T); 14 | 15 | impl Deref for Pointer { 16 | type Target = *mut T; 17 | 18 | fn deref(&self) -> &Self::Target { 19 | &self.0 20 | } 21 | } 22 | 23 | unsafe impl Send for Pointer {} 24 | unsafe impl Sync for Pointer {} 25 | -------------------------------------------------------------------------------- /picoquic-sys/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "picoquic-sys" 3 | version = "0.1.0" 4 | authors = ["Bastian Köcher "] 5 | build = "build.rs" 6 | license = "MIT/Apache-2.0" 7 | workspace = ".." 8 | categories = ["asynchronous", "network-programming"] 9 | repository = "https://github.com/bkchr/picoquic-rs" 10 | description = """ 11 | Provides bindings to the `picoquic` c-library. Please don't use this crate directly. 12 | Use the `picoquic` crate. 13 | """ 14 | edition = "2018" 15 | 16 | [dependencies] 17 | openssl-sys = "0.9.53" 18 | libc = "0.2" 19 | 20 | [build-dependencies] 21 | cc = { version = "1.0.47", features = ["parallel"] } 22 | glob = "0.3" 23 | bindgen = "0.52.0" 24 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "picoquic" 3 | version = "0.1.1" 4 | authors = ["Bastian Köcher "] 5 | license = "MIT/Apache-2.0" 6 | categories = ["asynchronous", "network-programming"] 7 | readme = "./README.md" 8 | description = """ 9 | Tokio aware picoquic bindings. Picoquic is a minimalist implementation of the QUIC protocol 10 | of the IETF. 11 | """ 12 | repository = "https://github.com/bkchr/picoquic-rs" 13 | keywords = ["quic", "future", "tokio", "protocol", "picoquic"] 14 | edition = "2018" 15 | 16 | [badges.travis-ci] 17 | repository = "bkchr/picoquic-rs" 18 | 19 | [dependencies] 20 | bytes = "0.4.12" 21 | failure = "0.1" 22 | failure_derive = "0.1" 23 | futures = "0.1" 24 | libc = "0.2" 25 | log = "0.4" 26 | openssl = "0.10.26" 27 | openssl-sys = "0.9.53" 28 | parking_lot = "0.9.0" 29 | socket2 = "0.3" 30 | tokio-executor = "0.1" 31 | tokio-timer = "0.2" 32 | tokio-udp = "0.1" 33 | smallvec = "1.0" 34 | 35 | [dependencies.picoquic-sys] 36 | path = "./picoquic-sys/" 37 | version = "0.1.0" 38 | 39 | [dev-dependencies] 40 | timebomb = "0.1" 41 | tokio = "0.1.22" 42 | rand = "0.7.2" 43 | 44 | [workspace] 45 | -------------------------------------------------------------------------------- /examples/client.rs: -------------------------------------------------------------------------------- 1 | use tokio; 2 | 3 | use picoquic::{Config, Context}; 4 | 5 | use bytes::Bytes; 6 | 7 | use futures::{Future, Sink, Stream}; 8 | 9 | fn main() { 10 | let mut evt_loop = tokio::runtime::Runtime::new().unwrap(); 11 | 12 | let manifest_dir = env!("CARGO_MANIFEST_DIR"); 13 | 14 | let mut config = Config::new(); 15 | config.set_root_certificate_filename(format!("{}/examples/ca_cert.pem", manifest_dir)); 16 | 17 | let mut client = Context::new(&([0, 0, 0, 0], 0).into(), evt_loop.executor(), config).unwrap(); 18 | 19 | let mut con = evt_loop 20 | .block_on(client.new_connection(([127, 0, 0, 1], 22222).into(), "server.test")) 21 | .unwrap(); 22 | 23 | let stream = evt_loop.block_on(con.new_bidirectional_stream()).unwrap(); 24 | 25 | let stream = evt_loop 26 | .block_on(stream.send(Bytes::from("hello server"))) 27 | .unwrap(); 28 | 29 | let answer = evt_loop 30 | .block_on( 31 | stream 32 | .into_future() 33 | .map(|(m, _)| m.unwrap()) 34 | .map_err(|(e, _)| e), 35 | ) 36 | .unwrap(); 37 | 38 | println!("Got: {:?}", answer); 39 | } 40 | -------------------------------------------------------------------------------- /examples/cert.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDQDCCAigCCQCowaMf2ivzuzANBgkqhkiG9w0BAQsFADBbMQswCQYDVQQGEwJU 3 | RTENMAsGA1UECAwEVGVzdDENMAsGA1UEBwwEVGVzdDENMAsGA1UECgwEVGVzdDEN 4 | MAsGA1UECwwEVGVzdDEQMA4GA1UEAwwHY2EudGVzdDAgFw0xODExMjEwODMxNDBa 5 | GA8yMTE4MTAyODA4MzE0MFowZzELMAkGA1UEBhMCREUxDzANBgNVBAgMBkNsaWVu 6 | dDEPMA0GA1UEBwwGQ2xpZW50MQ8wDQYDVQQKDAZDbGllbnQxDzANBgNVBAsMBkNs 7 | aWVudDEUMBIGA1UEAwwLc2VydmVyLnRlc3QwggEiMA0GCSqGSIb3DQEBAQUAA4IB 8 | DwAwggEKAoIBAQC5NLM3MiRmgrtzdZd3uKIqaYFp/AjgHJMNQw1L6fZpfG2Z2mfO 9 | NZ2wgN/DugZZ7tYMYEvxfBUiLtvc+GyT0IErWDk8W8Rspv4xzM20vccyOQcr9/hu 10 | 7bv9UBKB3JvQ8s0oiL1qjMrZJaD3RIJfqlIp1o71hobfUMz0pOrzUjNVandhs+2S 11 | SMTaeprs2kneZkAUnjtQDriIciISFjD6Xkdwa7SNjwo+bL60OTlZcinOsqF2Cg1B 12 | cSBCoTsIwlNNuwAnSUQ3A1lvhs6keBGpls7UNNemHK5QGtD6QHsA2tRUKF1suhpf 13 | umBfBiIZ/mR7CTdEYHaihLtW5IS+4lJeL543AgMBAAEwDQYJKoZIhvcNAQELBQAD 14 | ggEBAKSugxYwx6T2YxFxWwCz3vl8H/e6ERWtl7/3yqliJ+sjSu7QnJ476+yOHqz7 15 | x34F94kyEPCIj99KrMxdIBWB1Y8BcZIuyw7JM2LwSb/5hH0Ck7Yha44wKFVX8IGA 16 | 5Jg/27LJ/8UdfVQL9ea37J+WRCwZbjdELigK0M2hpqLdksD7Vi/C7fia0fRDh2RV 17 | ZKV2TUrfC6lfKvR2hiN5N5Z7bMhRxqSgwePYQtHjF6fC4sLUIxd3/5QGgcwWwx1T 18 | D/M+OBN7PBofoQ9OknWNCCnx5qXvwI+tgz+qprjor0RRAoGQctbqvytz3pBoXVpe 19 | 221VFpXLAMzvE8QYFCJUcznxElw= 20 | -----END CERTIFICATE----- 21 | -------------------------------------------------------------------------------- /tests/certs/device.invalid.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDWTCCAkECCQCYsQXl4gWnvTANBgkqhkiG9w0BAQsFADBeMQswCQYDVQQGEwJE 3 | RTEMMAoGA1UECAwDTE9MMQ8wDQYDVQQHDAZFU0VMT0wxDjAMBgNVBAoMBURFTE9M 4 | MREwDwYDVQQLDAhQSUNPUUxPTDENMAsGA1UEAwwETEFMRTAgFw0xODEwMjIxMzU4 5 | MTdaGA8yMTE4MDkyODEzNTgxN1owfTELMAkGA1UEBhMCREUxFTATBgNVBAgMDFBp 6 | Y29xdWljVGVzdDERMA8GA1UEBwwIVGVzdENpdHkxFTATBgNVBAoMDFBpY29xdWlj 7 | VGVzdDEVMBMGA1UECwwMUGljb3F1aWNUZXN0MRYwFAYDVQQDDA1waWNvcXVpYy50 8 | ZXN0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmVRF53J3WAn/45oI 9 | Do8mPeptTkEx51jQYZimMjkvfAOrFo1qyONkG+RXXnUq4w2d8vK5eyqUzhDxfwLw 10 | iljPFouXSdy6lY1iCZ7aTwxMZCr1KpABDLhCAs4E6JG1K3eN6jP+dHzAu9kq1Z7U 11 | ywNxLn9Acqd1ZsDlJnnwmwwWAIF72PaCFEkNrcjVIMN/q0LSQ6f4FrYKpVKQ8/fh 12 | sae7W+1Zzs/H10l9+u9bY3VVecozhnz3lOdN4xlp+utQ4/xVvmRXrvRNu2tOUqMA 13 | CKK0GqozHQllBff6AamkFlCnnhzzN1/82BKGOUnYFdGPlooYhL43d/99AktPimmn 14 | cOx10QIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQCOIVqfyPu060CA9Xpi+RI6AW9P 15 | oRyFs6OOThjH8u6Pn0Q+6Bm3rWDdEjMbSgE28WRmkF0obvt83E6SjLkt6UNOiu9H 16 | BF+AAp34c3cCw6iCeP9qVRESBi8AIuAsJX8LxPMdGNrzJ0LWXzufJdFnIuiz8N+y 17 | E3g4Tv7UfA8RX0moF1t9udi12QhM8v2AtpnFDsHkKLf7s7224CmPDN5L252Rb7OU 18 | JE3EFqQcYMleeAaL1noK2yw1jg9Olzxq46bQXdr8vN+eW6hhINKwWhg50d0ujq7I 19 | kQCvp6RjZX0+VUAWqbNV+m0cj39teljMsR3Dfr9Q2uSfNgRr8xWkp+hA3R2S 20 | -----END CERTIFICATE----- 21 | -------------------------------------------------------------------------------- /src/verify_certificate.rs: -------------------------------------------------------------------------------- 1 | use crate::{ConnectionId, ConnectionType}; 2 | 3 | pub use openssl::{ 4 | error::ErrorStack, 5 | stack::StackRef, 6 | x509::{store::X509StoreRef, X509Ref, X509StoreContext, X509StoreContextRef, X509}, 7 | *, 8 | }; 9 | 10 | /// The `VerifyCertificate` trait is used by the verify certificate handler, to verify a 11 | /// certificate. 12 | pub trait VerifyCertificate { 13 | /// Will be called to verify the given certificate and certificates chain. 14 | /// 15 | /// # Result 16 | /// 17 | /// If the certificate could be verified, the function should return `Ok(())`, otherwise 18 | /// a `Err(ErrorStack)` is expected. 19 | fn verify( 20 | &mut self, 21 | connection_id: ConnectionId, 22 | connection_type: ConnectionType, 23 | cert: &X509Ref, 24 | chain: &StackRef, 25 | ) -> Result; 26 | } 27 | 28 | /// Provides a default implementation for verifying a certificate and certificates chain against 29 | /// a `X509Store` with trusted certificates. 30 | pub fn default_verify_certificate( 31 | cert: &X509Ref, 32 | chain: &StackRef, 33 | store: &X509StoreRef, 34 | ) -> Result { 35 | let mut context = X509StoreContext::new()?; 36 | context.init(store, cert, chain, X509StoreContextRef::verify_cert) 37 | } 38 | -------------------------------------------------------------------------------- /examples/ca_cert.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDizCCAnOgAwIBAgIJAKUkcD7GarxLMA0GCSqGSIb3DQEBCwUAMFsxCzAJBgNV 3 | BAYTAlRFMQ0wCwYDVQQIDARUZXN0MQ0wCwYDVQQHDARUZXN0MQ0wCwYDVQQKDARU 4 | ZXN0MQ0wCwYDVQQLDARUZXN0MRAwDgYDVQQDDAdjYS50ZXN0MCAXDTE4MTEyMTA4 5 | MzAyOVoYDzIxMTgxMDI4MDgzMDI5WjBbMQswCQYDVQQGEwJURTENMAsGA1UECAwE 6 | VGVzdDENMAsGA1UEBwwEVGVzdDENMAsGA1UECgwEVGVzdDENMAsGA1UECwwEVGVz 7 | dDEQMA4GA1UEAwwHY2EudGVzdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC 8 | ggEBALk0szcyJGaCu3N1l3e4oippgWn8COAckw1DDUvp9ml8bZnaZ841nbCA38O6 9 | Blnu1gxgS/F8FSIu29z4bJPQgStYOTxbxGym/jHMzbS9xzI5Byv3+G7tu/1QEoHc 10 | m9DyzSiIvWqMytkloPdEgl+qUinWjvWGht9QzPSk6vNSM1Vqd2Gz7ZJIxNp6muza 11 | Sd5mQBSeO1AOuIhyIhIWMPpeR3BrtI2PCj5svrQ5OVlyKc6yoXYKDUFxIEKhOwjC 12 | U027ACdJRDcDWW+GzqR4EamWztQ016YcrlAa0PpAewDa1FQoXWy6Gl+6YF8GIhn+ 13 | ZHsJN0RgdqKEu1bkhL7iUl4vnjcCAwEAAaNQME4wHQYDVR0OBBYEFJEpNJAIrZWl 14 | FZZGwQxeBMY3vDU9MB8GA1UdIwQYMBaAFJEpNJAIrZWlFZZGwQxeBMY3vDU9MAwG 15 | A1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAGY5tTzdB4WJygE8YIZ3aeUV 16 | IwHshkm62dWbKKF/dLVWsI5ddd2cOaZn29Iwux0aptTOrgG9t6+8FV+5bbNeTWyX 17 | XChAD28XCCYdKe88b7c7EzHdrIGZmIK/uCPcJfXcLgq9rYvIffKailsaFVMcEeCV 18 | 9rt6fbX77VOVij+zCWpjFeZBFgpL84RcFFEB/SVKEeH7DUm7gkgdMV1cNpyXLry0 19 | i/DwfJ7deuGF92MIechq9aKZsaws6OieQhCOwyeV2W5pITo+i2qFInxnSvDCGa8X 20 | 1zZfsEy14zy24OXQc9qabA2znHBvb0UECu2FksfoN4e+d+0RoUHKgsIyu2IHH64= 21 | -----END CERTIFICATE----- 22 | -------------------------------------------------------------------------------- /tests/certs/device.test.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDhzCCAm8CCQCDJbu3vz4//DANBgkqhkiG9w0BAQsFADCBizELMAkGA1UEBhMC 3 | REUxGDAWBgNVBAgMDzpQaWNvcXVpY0NhVGVzdDEcMBoGA1UEBwwTOlBpY29xdWlj 4 | Q2FUZXN0Q2l0eTEYMBYGA1UECgwPOnBpY29xdWljY2F0ZXN0MQ8wDQYDVQQLDAZD 5 | YXRlc3QxGTAXBgNVBAMMEHBpY29xdWljLWNhLnRlc3QwIBcNMTgxMDIyMTM1NjM0 6 | WhgPMjExODA5MjgxMzU2MzRaMH0xCzAJBgNVBAYTAkRFMRUwEwYDVQQIDAxQaWNv 7 | cXVpY1Rlc3QxETAPBgNVBAcMCFRlc3RDaXR5MRUwEwYDVQQKDAxQaWNvcXVpY1Rl 8 | c3QxFTATBgNVBAsMDFBpY29xdWljVGVzdDEWMBQGA1UEAwwNcGljb3F1aWMudGVz 9 | dDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJlURedyd1gJ/+OaCA6P 10 | Jj3qbU5BMedY0GGYpjI5L3wDqxaNasjjZBvkV151KuMNnfLyuXsqlM4Q8X8C8IpY 11 | zxaLl0ncupWNYgme2k8MTGQq9SqQAQy4QgLOBOiRtSt3jeoz/nR8wLvZKtWe1MsD 12 | cS5/QHKndWbA5SZ58JsMFgCBe9j2ghRJDa3I1SDDf6tC0kOn+Ba2CqVSkPP34bGn 13 | u1vtWc7Px9dJffrvW2N1VXnKM4Z895TnTeMZafrrUOP8Vb5kV670TbtrTlKjAAii 14 | tBqqMx0JZQX3+gGppBZQp54c8zdf/NgShjlJ2BXRj5aKGIS+N3f/fQJLT4ppp3Ds 15 | ddECAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAvMnFKDiHfts8WbYTy9GZNOZYBtRe 16 | KpxSW877bFLvBzJC0C+bg0u3hUl0othQpSsUgJCV7IBPpS3KtUVYBKvMoQitVNWy 17 | 2Vko0Apixacbuc9FMzMhwX9Pi2n3o14bAWdg14Wp83qTeNvUKZPMTej9vgnlwj4k 18 | jVG1JplMuuCsPojQ/+GTOlLwcsMqsHnjKKLMy7cikA8UsjXKVDx2zYctr9xeREEi 19 | 5nl9os0Z61xfLpNO1neJESpElW/dz7rLnHWKhe5b0I9An1pB0C8WY03TgPMGUtN8 20 | BgfMiLpEYEEqgqTwDJOXMk6jXIXRORWemwwIyuiIieMdka7wYaOReXvVmw== 21 | -----END CERTIFICATE----- 22 | -------------------------------------------------------------------------------- /tests/certs/ca2.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDkTCCAnmgAwIBAgIJAKJ1vCCe6MJpMA0GCSqGSIb3DQEBCwUAMF4xCzAJBgNV 3 | BAYTAkRFMQwwCgYDVQQIDANMT0wxDzANBgNVBAcMBkVTRUxPTDEOMAwGA1UECgwF 4 | REVMT0wxETAPBgNVBAsMCFBJQ09RTE9MMQ0wCwYDVQQDDARMQUxFMCAXDTE4MDQw 5 | NjE3NDcwNFoYDzIxMTgwMzEzMTc0NzA0WjBeMQswCQYDVQQGEwJERTEMMAoGA1UE 6 | CAwDTE9MMQ8wDQYDVQQHDAZFU0VMT0wxDjAMBgNVBAoMBURFTE9MMREwDwYDVQQL 7 | DAhQSUNPUUxPTDENMAsGA1UEAwwETEFMRTCCASIwDQYJKoZIhvcNAQEBBQADggEP 8 | ADCCAQoCggEBAL8qnqo2XS/T4EwzCUvk4ZfzDkNUKryobspcPwEk2rU12JSWHS3r 9 | p8fsdyodSyqixn8Gl3r7tisVSma6CV2bH1PVzE2EnNDQE6Xzq2SDk8jW4HSUO+4U 10 | W0b1OD5T2AtAX5y+NiWvkb1dRCu7GE2paeZThWYBfZs3E0xXkhj96xlcT/vzn6T9 11 | JA3YyIJKwaI6Zdnn9LFmHoOaIhbH22t5ezNddzt0OKoMqMER3YqLyL6UsGM/hWzF 12 | yz3bBPYs1VaEFH9ofUrZi65K4V1FbnJunWaCD4Xfzyc0ZumUBeVH/2XYARJTr5xE 13 | ik9kBx4Rik8ugIImrzLY43il/Dj3fSRsUBUCAwEAAaNQME4wHQYDVR0OBBYEFLgo 14 | YVj/oBXfUHoJ7h1BOqyDSXlJMB8GA1UdIwQYMBaAFLgoYVj/oBXfUHoJ7h1BOqyD 15 | SXlJMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAACVurWeitN21hp8 16 | bB7v4c/SSBam2XAL6Z16n7ZNMxN2PUtgPZEHi7sYqFyf/PDaJ1jNtLsrMu3InQs6 17 | ohvHYa+6coOjTtmg4E3cI99TAyo1Z1QpJMHZE2whtPt/9EDfwDu+99XTSuOf2mvO 18 | WedLXZ0M4el1Xq2Jd302PirG2v4CuR5hw7qb5wpF2YmSlDAvt5GxFS6NfMBNiJDs 19 | 7tcn8gYbl/p3h2Kw8D+UQ9vUG31ghW8ndnCiWE7tF7dchGQIirX2+MovAMupu4WC 20 | nb1yuZzt5PN3WzTuR8YXPyNjjIq4QbW8MuUK5dGCWWb17iORE/vkCVlKmKHg7skb 21 | tctyGGw= 22 | -----END CERTIFICATE----- 23 | -------------------------------------------------------------------------------- /tests/certs/ca.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIID7TCCAtWgAwIBAgIJALdKRIHjRiGPMA0GCSqGSIb3DQEBCwUAMIGLMQswCQYD 3 | VQQGEwJERTEYMBYGA1UECAwPOlBpY29xdWljQ2FUZXN0MRwwGgYDVQQHDBM6UGlj 4 | b3F1aWNDYVRlc3RDaXR5MRgwFgYDVQQKDA86cGljb3F1aWNjYXRlc3QxDzANBgNV 5 | BAsMBkNhdGVzdDEZMBcGA1UEAwwQcGljb3F1aWMtY2EudGVzdDAgFw0xODEwMjIx 6 | MzQ5NDdaGA8yMTE4MDkyODEzNDk0N1owgYsxCzAJBgNVBAYTAkRFMRgwFgYDVQQI 7 | DA86UGljb3F1aWNDYVRlc3QxHDAaBgNVBAcMEzpQaWNvcXVpY0NhVGVzdENpdHkx 8 | GDAWBgNVBAoMDzpwaWNvcXVpY2NhdGVzdDEPMA0GA1UECwwGQ2F0ZXN0MRkwFwYD 9 | VQQDDBBwaWNvcXVpYy1jYS50ZXN0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB 10 | CgKCAQEAzyVlelU0ENt55uAAGmdLnspFLXgEfSNfPy2EaC0Qpm3kB8ziZo0Bvj3Q 11 | uGjtDeixJvZqZDbsljxrPaVdqJ9bnRVa+L91CGowFfV8Yfq3/H4xrW8PSnAiJXM7 12 | D4zZ7Tf+HEPKOl3IZePH4QRPawoTSz0CZObq82fdylnfmpFrU7K933RgIZXV1hdz 13 | a4o2HwPorlXYE+T2vjFLynKn+6i96Lf/sY+ly0o8Z5yD5kC6cn4sVUcmcYHGFZ4j 14 | eXowzWmBGAqdJXiBP3fndlx9zIDVEwWteQMR4reGdsiFPFix5AtZminjFwysCVyR 15 | Z/W/2qoBKahnCTnZQKnNJAKiDRdEvQIDAQABo1AwTjAdBgNVHQ4EFgQUEyszsrmn 16 | YVEchgVYGZ13meyk2a8wHwYDVR0jBBgwFoAUEyszsrmnYVEchgVYGZ13meyk2a8w 17 | DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAMf/yqDZz26KZvHbSLV0d 18 | c+2xVBlV9hCuprlfM8oCJRlne4AKky24he6KOsSPYzuhR/d1HBnE9VzI40BNHqxg 19 | wsASnDp4hb2FJlnUa0oPZpyCI2qWQ+7TE12h9dgX486NISw+vo1iXghzEXRZCnZY 20 | sq/3oKiqAHQMV1faefq/uZ3UANkQBXzeLX3ApbojlzuMjMLoAIwT+u1oFv8+dsS7 21 | jphsUs4hcG9hXhxqAwZqU3K7mFsqKeMQSVhDANeOuXcxtUW8V9W+hrITo6GFOYsB 22 | +lLOeFcM+964/oS3eOMEEXO7hny2dgvTlHVwQB8MZrZnXXA6RcLD+4FQCRNhYVh7 23 | 4A== 24 | -----END CERTIFICATE----- 25 | -------------------------------------------------------------------------------- /tests/certs/ca.key: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIEowIBAAKCAQEAzyVlelU0ENt55uAAGmdLnspFLXgEfSNfPy2EaC0Qpm3kB8zi 3 | Zo0Bvj3QuGjtDeixJvZqZDbsljxrPaVdqJ9bnRVa+L91CGowFfV8Yfq3/H4xrW8P 4 | SnAiJXM7D4zZ7Tf+HEPKOl3IZePH4QRPawoTSz0CZObq82fdylnfmpFrU7K933Rg 5 | IZXV1hdza4o2HwPorlXYE+T2vjFLynKn+6i96Lf/sY+ly0o8Z5yD5kC6cn4sVUcm 6 | cYHGFZ4jeXowzWmBGAqdJXiBP3fndlx9zIDVEwWteQMR4reGdsiFPFix5AtZminj 7 | FwysCVyRZ/W/2qoBKahnCTnZQKnNJAKiDRdEvQIDAQABAoIBADTtQC1uobwA5/e2 8 | mjAk3mx3EA/bD4KNzCNPVPptMUjk4ROhJOPA+YYLM046+P7JyqHC6lIqum50h44b 9 | t3+DIBxVvYW7HYMF5r1lmN9L+UCZWcYPj1+coQzikV+axH/ZA6NjKsOY/MAT4Bk9 10 | SbF2xJE/yGHRooyIqGGwbvKGX17l4ep8uczDZFB5IDFsHpwqc1zmxo01qgxhdP5H 11 | 8MqFPnrVbrFhujKAJsREH1brCMHmR/aRf6/3v+Y3e+RM1vfMmndPEYxZRmfDClVo 12 | MUM2hF5OPS9lvH9R6At3wA+cB8d0kKbAfitg5QWPNgv7EqeVUH0+ntI/J6mjZPoL 13 | VQutgR0CgYEA65Ryf2egF1AdZOUzNcLDFL2S/boyc7Bn0M9G1ZFi4qD7M8T4C0V8 14 | bBnk7VJ+yC61pvPNWztyi2RBEvA/PGFsoGDQp3HkSpbdyS6cynmv8QZhOCHaB+bA 15 | rfuTfjvd0CPXr6toZDPxIAflGAzarNS6s5Rr1vKnnif/3GymvkD88G8CgYEA4Rn/ 16 | v5bqpNN3Nen3yU2q279RMaVa5EFUuBeEM5wwKaVk3cyC4RrELZXg/pjbrmbWolLS 17 | mUXgRCBJ2IIgGszzp61Pv2BWdAJl1NRE+OiwZQXcSH2YjWZ4d96o33IpSHbjz+s4 18 | 2fXpOjzfdGo1Z/Q/MqL+hcVMv2NIziiISQUam5MCgYB38eU6KTDBrfDJZklknf1l 19 | mgA1X5BAhxjUoDSYmKWYbg54lVkVpBNtluGQU+hpVB75Gjj8so/nmOvpEJmhzJja 20 | L3ENUFfEAnx56lm6XarPNUhapCG21C5WZzj5lNGjIBy5PLSyECA9BsgGLsVIKifF 21 | N1SQ5IujYwpK2KctRzmB0QKBgQC+1jTdL8wEKwdQ3OdmcYMdw8fJKB+zjbOOUtmQ 22 | i6TFWeP2qjB3OSMCZqOWFO+BnsvuV/sVWIk2GI2ikUc4kXMsP6FxZPJGbdX5JnDG 23 | +Ta6nspPZrNThYEyVsGilf1r4udmWUwcdP/ikML8xiI63HZLrqXLsSZMx5ZsuS45 24 | gas6IwKBgEE/qZrZewdyz5NhFXaGpMilxGPSsbjkcoEv4HADEKPOoxUeYp/BcEnR 25 | ljk0BGNkzuFzB/ZDAxPOusSmWSs4SCUcs/r3GntAXsg2iV6qnofXXX6b4Sqs0Cnj 26 | CP2szbgI0iDqXGcq93XxvB7PaGWwg3+2E5vj1dM/+XO/c3qajo7a 27 | -----END RSA PRIVATE KEY----- 28 | -------------------------------------------------------------------------------- /tests/certs/ca2.key: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIEowIBAAKCAQEAvyqeqjZdL9PgTDMJS+Thl/MOQ1QqvKhuylw/ASTatTXYlJYd 3 | Leunx+x3Kh1LKqLGfwaXevu2KxVKZroJXZsfU9XMTYSc0NATpfOrZIOTyNbgdJQ7 4 | 7hRbRvU4PlPYC0BfnL42Ja+RvV1EK7sYTalp5lOFZgF9mzcTTFeSGP3rGVxP+/Of 5 | pP0kDdjIgkrBojpl2ef0sWYeg5oiFsfba3l7M113O3Q4qgyowRHdiovIvpSwYz+F 6 | bMXLPdsE9izVVoQUf2h9StmLrkrhXUVucm6dZoIPhd/PJzRm6ZQF5Uf/ZdgBElOv 7 | nESKT2QHHhGKTy6AgiavMtjjeKX8OPd9JGxQFQIDAQABAoIBAH+q/vu+As4GOi2p 8 | h/Pfj6ni8QuWElScSCFtKcahzk5m/5V8C1C3qP2jtpGxrplyzA3ZYSEJKcfsGBwy 9 | 8j5JcsqSZjb+8Zui2vxhl30xQmlG1/ADb2K4xZzF+CHn7MjW3QPZJGBWuIY222g5 10 | Mynqkob4EIbnR/N4/LJnaXK3YWM1U7HSyFngIy+FwvtS+S28saOv1xWD7+gOPl4w 11 | AZBv4gS0J10maIUXpU47xXYb5XOZ2uwCO2VYHFepeQToDpkm6kI0eSk0ZEMofi/K 12 | wcjt9l4idlmVcBpuOzCATOrqc3x07biuHKmQkRjpk/7yVkYe8fye2p6wh67Lcnu0 13 | 6oVIh6ECgYEA5Ifb9x5an5j3mT0k5zBFS28lp0+zLvsNA101Qhw8qUbWJuQk3Nt4 14 | jpfa67W1mG4ukzh4PpWYL5yGQw4bS7jf1kisyfCiVMJNnPPo9GbSNOcrGMHmmZ5Z 15 | q70sjDqAvs0O6OlcqMji974PS8TWtxEfYaqwHw3Q3+KeFMPbSfvH9KMCgYEA1iUF 16 | xV6T73jl8VuSwlfQJBnMxHuyn4rO30uq1rLBjhhiLxBu0Qwz7iRXiYVIM0/LbXmX 17 | 1TtK+8oZj7U+88e457w9G6puiactUJ9mkxq58Cu3nD7r0RKS01NclnjmzLLwnvt1 18 | 5VML4WdjuTFrXWrDCSfw1eEeEAlm7nsyV8i/O+cCgYBmDGjkO9C57eO6sPwWpI58 19 | 9d/5i3R3KTIRa4DJybQo3vHoIf54BSUbf6IJmXXC4Ii5wwCm6cQwlpO5w8XalW6W 20 | 0JMgBe1nLfDcgmpnILcDWqr6/jMMLBLcxrfq0oEFMqpSxUpUMIhxmpRYAEjlLKc3 21 | xLGq3E+GejqfCSqWKfGLQwKBgQCboSpxh0vCNT3/y8p73S/SnMF5ZmCpnEq+c5KE 22 | GEOczlHE3I988/5lqxnHQwr2553zQPQ8rqvPE9DB5ToMF3FlUSOkEJfnCI1hU4dL 23 | j5fkWRFGx1/AgVwdoy7d2J371GwVTrEe6dzvgqEx/R2HNcjqxZE9Dy82/m5FEVnD 24 | /IwmrwKBgAZxmreO2bShpeO1bX+nSKz7O6yv+d8spOFrk6tvR4sdS+G3Q2iuaXUQ 25 | T9d4PU+VOzOKwATsy+k4cTNG5x5BmEgtzUaXMGLJ4KeNZjWzKlME5q6fe/QQo3f8 26 | TLfiBNEslDrskdeAu5v83R192ppr5apSOJZF5uE7/pZy5IIpq1+B 27 | -----END RSA PRIVATE KEY----- 28 | -------------------------------------------------------------------------------- /tests/certs/device.key: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIEogIBAAKCAQEAmVRF53J3WAn/45oIDo8mPeptTkEx51jQYZimMjkvfAOrFo1q 3 | yONkG+RXXnUq4w2d8vK5eyqUzhDxfwLwiljPFouXSdy6lY1iCZ7aTwxMZCr1KpAB 4 | DLhCAs4E6JG1K3eN6jP+dHzAu9kq1Z7UywNxLn9Acqd1ZsDlJnnwmwwWAIF72PaC 5 | FEkNrcjVIMN/q0LSQ6f4FrYKpVKQ8/fhsae7W+1Zzs/H10l9+u9bY3VVecozhnz3 6 | lOdN4xlp+utQ4/xVvmRXrvRNu2tOUqMACKK0GqozHQllBff6AamkFlCnnhzzN1/8 7 | 2BKGOUnYFdGPlooYhL43d/99AktPimmncOx10QIDAQABAoIBAGE1qrQYQE3S2Scl 8 | quIAI9CxZedtMgRorIST0RqaYt6PPNMpiYAfmoKMfE/onO4i3fb/qFTMJFeZKmLK 9 | LFKqB3FVwu8TQEA8yOEsk1/2fiArlBAOCHxV/ZPlpfsFFgWe4JyRpkuYJGF0R9Hz 10 | xxmG7yT5jJSkUqx4s093k/HY8cITWoaD6ER/dtQTJFLx4fH1clAY4KYqmmzbHQrx 11 | V/8fJddnicPBjA77N1WvuiG2uMSrFnrOi1sICtBFW14ln5r+ibJazja+0CZ6onj9 12 | ZtCKngbrkLMu5oBGu9thCWw96j062EoBi0KIuznzBNDqrFrCv3TQTtNkovA3kgDB 13 | MsG9RyECgYEAxzNfD72YYy1OF/P8gVXtKQw1MSviLoRqWZ4FFW2hCCUHXvnazxVa 14 | DGprJmyUWol5o9qqGjcMTSKqT9tMDJuzMrKatAXQSGeryRQtPRq7RPForYkX7J0X 15 | 8BzNp29IncdOz+lhQhfoQBNUUBmujmkdHRSUnZsG8nXlyoR/KItg1lUCgYEAxQyE 16 | z2hyz6tcqENZ0qz52091I2p3+spOsNKspwY1nkNGIy4aJlwhm0hvgZbR1TkqjTHs 17 | VZZrYvwZN2ekHGpOpzMLRxvxcZjV55RyfB/jOo8qYel2wKMN7USi+mO63ziHP+AU 18 | T4tc/rK+AFOtz0yoDg9lNQrTgpIMqSNrxioLxY0CgYB6UO8ESVUzQPR8/NKF0G9q 19 | DxbydJHUInbzRHa2q7R/vc0C4sUa929txEK7O1z1IwlQNcrRgg/JpYmSs4PFEi48 20 | 6TLZa+BzNUVkmUEWDj4DnYC7Xj0Ui3nRdL5LG6gpSeL5A8M2xFtWTQgujzaCN8Uq 21 | wCJpjHH9m6tYaXdzO/JgaQKBgBsdP+EyZCoDUHqu2dtNhgwRgPLgoaXW1MEsHCnX 22 | huVCKJKKs3p3zwAJFZ7lW/ZVKW/IYNbeHeS+/9FJ56EpV61WLsUYKT8SYsy89ovx 23 | 71iNfq1+bKLRTQdLHIoL0xkINEQr11+is6cwfUiaOx59U9qrb6e+15/t7OQRRbE8 24 | 8+W5AoGAU00wvFnMlDOCBaobFSmHSDaFDqU67P+NcTvATmscuVpHWl6wbQiRV/zZ 25 | ZPWR4goV2BKA9wcEq+jfaEF12lbD1ufROxSD9cAf8/ssJLgSYlmvsxvvSMEmhQuW 26 | yBJ7imIdU5XUDp0/EIzBMK5+zmG2VhtZtpADHrJoyClCm1mRzHE= 27 | -----END RSA PRIVATE KEY----- 28 | -------------------------------------------------------------------------------- /examples/key.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC5NLM3MiRmgrtz 3 | dZd3uKIqaYFp/AjgHJMNQw1L6fZpfG2Z2mfONZ2wgN/DugZZ7tYMYEvxfBUiLtvc 4 | +GyT0IErWDk8W8Rspv4xzM20vccyOQcr9/hu7bv9UBKB3JvQ8s0oiL1qjMrZJaD3 5 | RIJfqlIp1o71hobfUMz0pOrzUjNVandhs+2SSMTaeprs2kneZkAUnjtQDriIciIS 6 | FjD6Xkdwa7SNjwo+bL60OTlZcinOsqF2Cg1BcSBCoTsIwlNNuwAnSUQ3A1lvhs6k 7 | eBGpls7UNNemHK5QGtD6QHsA2tRUKF1suhpfumBfBiIZ/mR7CTdEYHaihLtW5IS+ 8 | 4lJeL543AgMBAAECggEARINOWPjfplxuY8P4iH1w4CevjDmEPwPTEnDfllmyoks5 9 | cFTvWcVT1FuYa5uBhftoi6OD9I1mdALJqvDrmbLkVdiJM97uxxLvrhSJdHdQHTAj 10 | iwxshvzDMm5QqmGl8qIfawNKrwPudm4JIe/iGumzA28v63wcoLgPWeE4WVLrUoky 11 | WUc4eOhdqgB1I1Ma/pOZGIMMF8kdmvqau7XSrc7u51wAQgf8Y+MF6E2WWwKLfd75 12 | oWlmyJtzY0zVQ+brHmRPMiwvWwtoahLS1rVvkLf62bWlUcVT4IEDNhd0Igftee7n 13 | 0G+GEpaVjL+FGdnzJ9EVsTH7CQ7fPS0E1fvm0BK7IQKBgQDvId7NHGUgkw2Ekdu0 14 | CXrSo52ZEDEFt0yyv1RYCWk+IWF3IOj2QIGQ5cR9fQPI0sKXU4poMgIbEv2NRnVY 15 | JIQ11Z8tXQe9+Hk56MvhjQhni6WwmuoNTw6yGlWFMWZgkKauSNaQW0v+CdCDlG2o 16 | I1Iuv4nT1sq9orT2uxQVr6PNqwKBgQDGRQ2p+9CQyFqjg8A39niLrqAH4nd4O5/H 17 | Mc5orbLNAxEWH09MFZPl11+WTksVlhPcrvKczYUcQsVAW1MIB46VtRjyJ8wC+RE+ 18 | +ayLR26PpPgUgfuz/dPytDdi2e3Y5vtZ6ZDwVfwBEUfYoC9TcunJWaIXIJpvyUJp 19 | 3sxJJF8tpQKBgQDUUiFtwnFz271b4NnO37/i+Iz8k2jDZ329E65CwJBmLuNID7to 20 | sduYmLm+pdpPW/qUvAMfAo/mFBV2c4HK8hlFZ1f+wiQWo2CXb0BfEobM0SwbQ2De 21 | 0jv9HO6j5Tm+MZEdG+UOpVEyzOoLeiVm7X2RrlUk9whqGeZNT8vEeX+aIwKBgQCc 22 | ueckME7cs9OaH8JpOmZtnBsaQHVJ0G/ryL4t1uhY0IzIHPXU4dWoQMhpivglVx3a 23 | O1zCgF8xSMKdrdMDrN2UD7RpbvYAf5uXWUuASXXnDHOh2mH6FLJezwBdHoG6DFQx 24 | 7cRJht6OhXdykKT4ZQTSygysFXSe2sup3plDVAH8lQKBgECy9w2481N3RoET7Z0x 25 | 1RHQSLNduFBOekdBMmJzbQJm1r5G+j9iUrwESboi5ZwodpMT3DS+rXye6GmJhOKi 26 | e+M3uATC+lsHnU3AInf/t3N8NvYS9AOIkWV/p/+IjzMPTyEJH2nUBUZA8f32bcnL 27 | 3qG4F2xvUiz0/vVrbQyJm/LQ 28 | -----END PRIVATE KEY----- 29 | -------------------------------------------------------------------------------- /src/swappable_stream.rs: -------------------------------------------------------------------------------- 1 | use futures::{Async::Ready, Poll, Stream}; 2 | 3 | use std::{ 4 | fmt, 5 | ops::{Deref, DerefMut}, 6 | }; 7 | 8 | pub struct SwappableStream { 9 | active_stream: S, 10 | swap_to: Option, 11 | } 12 | 13 | impl fmt::Debug for SwappableStream { 14 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 15 | write!(f, "SwappableStream") 16 | } 17 | } 18 | 19 | impl SwappableStream { 20 | pub fn new(active_stream: S) -> Self { 21 | Self { 22 | active_stream, 23 | swap_to: None, 24 | } 25 | } 26 | 27 | pub fn set_swap_to(&mut self, swap_to: S) { 28 | self.swap_to = Some(swap_to); 29 | } 30 | } 31 | 32 | impl Stream for SwappableStream { 33 | type Item = ::Item; 34 | type Error = ::Error; 35 | 36 | fn poll(&mut self) -> Poll, Self::Error> { 37 | loop { 38 | match try_ready!(self.active_stream.poll()) { 39 | Some(val) => return Ok(Ready(Some(val))), 40 | None => match self.swap_to.take() { 41 | Some(new_stream) => self.active_stream = new_stream, 42 | None => return Ok(Ready(None)), 43 | }, 44 | } 45 | } 46 | } 47 | } 48 | 49 | impl From for SwappableStream { 50 | fn from(stream: S) -> Self { 51 | SwappableStream::new(stream) 52 | } 53 | } 54 | 55 | impl Deref for SwappableStream { 56 | type Target = S; 57 | 58 | fn deref(&self) -> &Self::Target { 59 | &self.active_stream 60 | } 61 | } 62 | 63 | impl DerefMut for SwappableStream { 64 | fn deref_mut(&mut self) -> &mut S { 65 | &mut self.active_stream 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /examples/server.rs: -------------------------------------------------------------------------------- 1 | use tokio; 2 | 3 | use picoquic::{Config, Context}; 4 | 5 | use futures::{Future, Sink, Stream}; 6 | 7 | use bytes::Bytes; 8 | 9 | fn main() { 10 | let evt_loop = tokio::runtime::Runtime::new().unwrap(); 11 | 12 | let manifest_dir = env!("CARGO_MANIFEST_DIR"); 13 | 14 | let mut config = Config::new(); 15 | config.set_certificate_chain_filename(format!("{}/examples/cert.pem", manifest_dir)); 16 | config.set_private_key_filename(format!("{}/examples/key.pem", manifest_dir)); 17 | 18 | let server = Context::new(&([0, 0, 0, 0], 22222).into(), evt_loop.executor(), config).unwrap(); 19 | 20 | println!("Server listening on: {}", server.local_addr()); 21 | 22 | evt_loop 23 | .block_on_all(server.for_each(|c| { 24 | println!("New connection from: {}", c.peer_addr()); 25 | 26 | tokio::spawn( 27 | c.for_each(move |s| { 28 | // We print the received message and sent a new one, after that we collect all 29 | // remaining messages. The collect is a "hack" that prevents that the `Stream` is 30 | // dropped too early. 31 | tokio::spawn( 32 | s.into_future() 33 | .map_err(|_| ()) 34 | .and_then(|(m, s)| { 35 | println!("Got: {:?}", m); 36 | s.send(Bytes::from("hello client")).map_err(|_| ()) 37 | }) 38 | .and_then(|s| s.collect().map_err(|_| ())) 39 | .map(|_| ()), 40 | ); 41 | Ok(()) 42 | }) 43 | .map_err(|_| ()), 44 | ); 45 | 46 | Ok(()) 47 | })) 48 | .unwrap(); 49 | } 50 | -------------------------------------------------------------------------------- /src/ffi/stateless_packet.rs: -------------------------------------------------------------------------------- 1 | use super::quic_ctx::socket_addr_from_sockaddr_storage; 2 | use picoquic_sys::picoquic::{ 3 | picoquic_delete_stateless_packet, picoquic_dequeue_stateless_packet, picoquic_quic_t, 4 | picoquic_stateless_packet_t, 5 | }; 6 | 7 | use std::iter::Iterator; 8 | use std::marker::PhantomData; 9 | use std::mem; 10 | use std::net::SocketAddr; 11 | use std::slice; 12 | 13 | use libc; 14 | 15 | pub struct StatelessPacket { 16 | packet: *mut picoquic_stateless_packet_t, 17 | } 18 | 19 | impl StatelessPacket { 20 | fn new(packet: *mut picoquic_stateless_packet_t) -> StatelessPacket { 21 | StatelessPacket { packet } 22 | } 23 | 24 | pub fn get_peer_addr(&self) -> SocketAddr { 25 | let socket_family = unsafe { (*self.packet).addr_to.ss_family }; 26 | 27 | let socket_len = if i32::from(socket_family) == libc::AF_INET { 28 | mem::size_of::() 29 | } else { 30 | mem::size_of::() 31 | }; 32 | 33 | socket_addr_from_sockaddr_storage(unsafe { &(*self.packet).addr_to }, socket_len as i32) 34 | } 35 | 36 | pub fn get_data(&self) -> &[u8] { 37 | unsafe { 38 | slice::from_raw_parts( 39 | &(*self.packet).bytes as *const [u8; 1536] as *const u8, 40 | (*self.packet).length, 41 | ) 42 | } 43 | } 44 | } 45 | 46 | impl Drop for StatelessPacket { 47 | fn drop(&mut self) { 48 | unsafe { 49 | picoquic_delete_stateless_packet(self.packet); 50 | } 51 | } 52 | } 53 | 54 | pub struct StatelessPacketIter<'a> { 55 | quic: *mut picoquic_quic_t, 56 | _marker: PhantomData<&'a i32>, 57 | } 58 | 59 | impl<'a> StatelessPacketIter<'a> { 60 | pub fn new(quic: *mut picoquic_quic_t) -> StatelessPacketIter<'a> { 61 | StatelessPacketIter { 62 | quic, 63 | _marker: Default::default(), 64 | } 65 | } 66 | } 67 | 68 | impl<'a> Iterator for StatelessPacketIter<'a> { 69 | type Item = StatelessPacket; 70 | 71 | fn next(&mut self) -> Option { 72 | let res = unsafe { picoquic_dequeue_stateless_packet(self.quic) }; 73 | if res.is_null() { 74 | None 75 | } else { 76 | Some(StatelessPacket::new(res)) 77 | } 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/context.rs: -------------------------------------------------------------------------------- 1 | use crate::config::Config; 2 | use crate::connection::Connection; 3 | use crate::context_inner::{ContextInner, NewConnectionFuture, NewConnectionHandle}; 4 | use crate::error::*; 5 | 6 | use std::net::SocketAddr; 7 | 8 | use tokio_executor::Executor; 9 | 10 | use futures::{ 11 | sync::{mpsc::UnboundedReceiver, oneshot}, 12 | Async::{NotReady, Ready}, 13 | Future, Poll, Stream, 14 | }; 15 | 16 | /// The `Picoquic` context. It setups and controls the `UdpSocket`. Every incoming `Connection` 17 | /// can be obtained by polling this context. 18 | pub struct Context { 19 | recv_con: UnboundedReceiver, 20 | local_addr: SocketAddr, 21 | new_connection_handle: NewConnectionHandle, 22 | /// The handle is used to inform the `ContextInner` about `Context` being dropped. 23 | close_handle: oneshot::Receiver<()>, 24 | } 25 | 26 | impl Context { 27 | /// Creates a new `Context`. 28 | /// 29 | /// name - Will be used as SNI for TLS. 30 | pub fn new( 31 | listen_address: &SocketAddr, 32 | mut handle: impl Executor, 33 | config: Config, 34 | ) -> Result { 35 | // Check for common errors in the `Config`. 36 | config.verify()?; 37 | 38 | let (inner, recv_con, new_connection_handle, close_handle) = 39 | ContextInner::new(listen_address, config)?; 40 | 41 | let local_addr = inner.local_addr(); 42 | 43 | // start the inner future 44 | handle.spawn(Box::new(inner))?; 45 | 46 | Ok(Context { 47 | recv_con, 48 | local_addr, 49 | new_connection_handle, 50 | close_handle, 51 | }) 52 | } 53 | 54 | /// Returns the local address, this `Context` is bound to. 55 | pub fn local_addr(&self) -> SocketAddr { 56 | self.local_addr 57 | } 58 | 59 | /// Connects to the given address and returns a future that resolves into a `Connection`. 60 | /// 61 | /// addr - Address of the server. 62 | /// server_name - The name of the server that will be used by TLS to verify the certificate. 63 | pub fn new_connection>( 64 | &mut self, 65 | addr: SocketAddr, 66 | server_name: T, 67 | ) -> NewConnectionFuture { 68 | self.new_connection_handle.new_connection(addr, server_name) 69 | } 70 | 71 | /// Returns the handle to create new connections. 72 | pub fn get_new_connection_handle(&self) -> NewConnectionHandle { 73 | self.new_connection_handle.clone() 74 | } 75 | } 76 | 77 | impl Stream for Context { 78 | type Item = Connection; 79 | type Error = Error; 80 | 81 | fn poll(&mut self) -> Poll, Self::Error> { 82 | match self.close_handle.poll() { 83 | Ok(Ready(())) | Err(_) => return Ok(Ready(None)), 84 | Ok(NotReady) => {} 85 | }; 86 | 87 | self.recv_con.poll().map_err(|_| ErrorKind::Unknown.into()) 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /src/error.rs: -------------------------------------------------------------------------------- 1 | use std::{ffi, fmt, io, mem}; 2 | 3 | pub use failure::ResultExt; 4 | use failure::{self, Backtrace, Context, Fail}; 5 | 6 | use bytes::Bytes; 7 | 8 | use futures; 9 | 10 | use openssl; 11 | 12 | use tokio_executor::SpawnError; 13 | 14 | #[derive(Debug)] 15 | pub struct Error { 16 | inner: Context, 17 | } 18 | 19 | impl Fail for Error { 20 | fn cause(&self) -> Option<&dyn Fail> { 21 | self.inner.cause() 22 | } 23 | 24 | fn backtrace(&self) -> Option<&Backtrace> { 25 | self.inner.backtrace() 26 | } 27 | } 28 | 29 | impl fmt::Display for Error { 30 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 31 | fmt::Display::fmt(&self.inner, f) 32 | } 33 | } 34 | 35 | impl Error { 36 | pub fn kind(&self) -> &ErrorKind { 37 | &self.inner.get_context() 38 | } 39 | } 40 | 41 | impl From for Error { 42 | fn from(kind: ErrorKind) -> Error { 43 | Error { 44 | inner: Context::new(kind), 45 | } 46 | } 47 | } 48 | 49 | impl From> for Error { 50 | fn from(inner: Context) -> Error { 51 | Error { inner } 52 | } 53 | } 54 | 55 | impl From for Error { 56 | fn from(_: futures::Canceled) -> Error { 57 | ErrorKind::InternalError.into() 58 | } 59 | } 60 | 61 | impl From for Error { 62 | fn from(_: ffi::NulError) -> Error { 63 | ErrorKind::FFIError.into() 64 | } 65 | } 66 | 67 | impl From for Error { 68 | fn from(_: openssl::error::ErrorStack) -> Error { 69 | ErrorKind::OpenSSLError.into() 70 | } 71 | } 72 | 73 | impl From for Error { 74 | fn from(e: failure::Error) -> Error { 75 | ErrorKind::Custom(e).into() 76 | } 77 | } 78 | 79 | impl From for Error { 80 | fn from(e: io::Error) -> Error { 81 | ErrorKind::Io(e).into() 82 | } 83 | } 84 | 85 | impl From for Error { 86 | fn from(e: SpawnError) -> Error { 87 | ErrorKind::Spawn(e).into() 88 | } 89 | } 90 | 91 | #[derive(Debug, Fail)] 92 | pub enum ErrorKind { 93 | #[fail(display = "A network error occurred.")] 94 | NetworkError, 95 | #[fail(display = "A ffi error occurred.")] 96 | FFIError, 97 | #[fail(display = "Could not allocate new memory.")] 98 | OutOfMemoryError, 99 | #[fail(display = "Disconnected.")] 100 | Disconnected, 101 | #[fail(display = "Unknown.")] 102 | Unknown, 103 | #[fail(display = "Send failed.")] 104 | SendError(Bytes), 105 | #[fail(display = "An error occurred in the TLS handshake.")] 106 | TLSHandshakeError, 107 | #[fail(display = "An internal error occurred.")] 108 | InternalError, 109 | #[fail(display = "A string contains none unicode symbols.")] 110 | NoneUnicode, 111 | #[fail(display = "An OpenSSL error occurred.")] 112 | OpenSSLError, 113 | #[fail(display = "Error {}", _0)] 114 | Custom(failure::Error), 115 | #[fail(display = "IO error {}", _0)] 116 | Io(io::Error), 117 | #[fail(display = "Spawn error {}", _0)] 118 | Spawn(SpawnError), 119 | #[fail(display = "Tried to send data on an unidirectional receiving side Stream.")] 120 | SendOnUnidirectional, 121 | } 122 | 123 | impl PartialEq for ErrorKind { 124 | fn eq(&self, other: &Self) -> bool { 125 | mem::discriminant(self) == mem::discriminant(other) 126 | } 127 | } 128 | 129 | //FIXME: Remove when upstream provides a better bail macro 130 | macro_rules! bail { 131 | ($e:expr) => { 132 | return Err(::failure::err_msg::<&'static str>($e).into()); 133 | }; 134 | ($fmt:expr, $($arg:tt)+) => { 135 | return Err(::failure::err_msg::(format!($fmt, $($arg)+)).into()); 136 | }; 137 | } 138 | 139 | /// A function that returns the an error. 140 | pub trait ErrorFn: Send + 'static + Sync + Fn() -> Error {} 141 | impl Error + Send + 'static + Sync> ErrorFn for T {} 142 | -------------------------------------------------------------------------------- /picoquic-sys/build.rs: -------------------------------------------------------------------------------- 1 | use bindgen; 2 | use cc; 3 | use glob; 4 | 5 | use std::env; 6 | use std::path::PathBuf; 7 | 8 | fn main() { 9 | let debug = match env::var("DEBUG").ok() { 10 | Some(val) => val != "false", 11 | None => false, 12 | }; 13 | 14 | let target = env::var("TARGET").unwrap(); 15 | 16 | let openssl_include = env::var("DEP_OPENSSL_INCLUDE"); 17 | 18 | if let Err(_) = openssl_include { 19 | println!( 20 | "cargo:warning=Could not find openssl include directory via `DEP_OPENSSL_INCLUDE`." 21 | ) 22 | } 23 | 24 | // build picotls 25 | let mut picotls = cc::Build::new(); 26 | picotls 27 | .flag("-Wno-unused-parameter") 28 | .flag("-Wno-missing-field-initializers") 29 | .flag("-Wno-sign-compare") 30 | .opt_level(1) 31 | .file("src/picotls/lib/picotls.c") 32 | .file("src/picotls/lib/pembase64.c") 33 | .file("src/picotls/lib/openssl.c") 34 | .file("src/picotls/lib/cifra.c") 35 | .file("src/picotls/lib/cifra/aes128.c") 36 | .file("src/picotls/lib/cifra/chacha20.c") 37 | .file("src/picotls/lib/cifra/random.c") 38 | .file("src/picotls/lib/cifra/x25519.c") 39 | .file("src/picotls/deps/cifra/src/curve25519.c") 40 | .file("src/picotls/deps/cifra/src/chacha20.c") 41 | .file("src/picotls/deps/cifra/src/sha256.c") 42 | .file("src/picotls/deps/cifra/src/sha512.c") 43 | .file("src/picotls/deps/cifra/src/poly1305.c") 44 | .file("src/picotls/deps/cifra/src/drbg.c") 45 | .file("src/picotls/deps/cifra/src/blockwise.c") 46 | .include("src/picotls/deps/cifra/src/") 47 | .include("src/picotls/deps/cifra/src/ext/") 48 | .include("src/picotls/lib/cifra/") 49 | .include("src/picotls/include/"); 50 | 51 | if let Ok(ref openssl_include) = openssl_include { 52 | picotls.include(&openssl_include); 53 | } 54 | 55 | if target.contains("android") { 56 | picotls.flag("-std=c99"); 57 | } 58 | 59 | picotls.compile("picotls"); 60 | 61 | // build picoquic 62 | let mut picoquic = cc::Build::new(); 63 | picoquic 64 | .flag("-Wno-unused-parameter") 65 | .flag("-Wno-sign-compare") 66 | .flag("-Wno-unused-but-set-variable") 67 | .flag("-Wno-missing-field-initializers") 68 | .opt_level(1) 69 | .files( 70 | glob::glob("src/picoquic/picoquic/*.c") 71 | .expect("failed to find picoquic c files") 72 | .filter_map(|p| match p { 73 | Ok(p) => Some(p), 74 | _ => None, 75 | }), 76 | ) 77 | .include("src/picoquic/picoquic") 78 | .include("src/picotls/include/"); 79 | 80 | if let Ok(ref openssl_include) = openssl_include { 81 | picoquic.include(&openssl_include); 82 | } 83 | 84 | if target.contains("android") { 85 | picoquic.flag("-std=c99"); 86 | } 87 | 88 | if debug { 89 | picoquic.define("_DEBUG", None); 90 | } else { 91 | picoquic.define("DISABLE_DEBUG_PRINTF", None); 92 | } 93 | 94 | picoquic.compile("picoquic"); 95 | 96 | let extra_cflags = env::var("PICOQUIC_BINDGEN_CFLAGS").unwrap_or("".into()); 97 | 98 | // generate the rust bindings for the picoquic 99 | let bindings = bindgen::Builder::default() 100 | .clang_arg("-DNULL=0") 101 | .header("src/picotls/include/picotls.h") 102 | .header("src/picoquic/picoquic/picoquic.h") 103 | .header("src/picoquic/picoquic/util.h") 104 | .blacklist_type("sockaddr_storage") 105 | .blacklist_type("__kernel_sockaddr_storage") 106 | .raw_line("pub type sockaddr_storage = ::libc::sockaddr_storage;") 107 | .raw_line("pub type __kernel_sockaddr_storage = sockaddr_storage;") 108 | .clang_args(extra_cflags.split(" ")) 109 | .generate() 110 | .expect("Generates picoquic bindings"); 111 | 112 | let out_path = PathBuf::from(env::var("OUT_DIR").unwrap()); 113 | bindings 114 | .write_to_file(out_path.join("picoquic.rs")) 115 | .expect("Couldn't write bindings!"); 116 | } 117 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Picoquic-rs - Tokio aware bindings of [picoquic](https://github.com/private-octopus/picoquic) 2 | [![](https://docs.rs/picoquic/badge.svg)](https://docs.rs/picoquic/) [![](https://img.shields.io/crates/v/picoquic.svg)](https://crates.io/crates/picoquic) [![](https://img.shields.io/crates/d/picoquic.png)](https://crates.io/crates/picoquic) [![Build Status](https://travis-ci.org/bkchr/picoquic-rs.png?branch=master)](https://travis-ci.org/bkchr/picoquic-rs) 3 | 4 | Picoquic is a minimalist implementation of the QUIC protocol by the IETF. The protocol is still 5 | in [development](https://github.com/quicwg) and so the implementation. 6 | 7 | * [Building](#building) 8 | * [Example](#example) 9 | * [Todo](#todo) 10 | * [License](#license) 11 | * [Contribution](#contribution) 12 | 13 | ### Building 14 | 15 | For building picoquic-rs, you need the following dependencies: 16 | * clang 17 | * openssl 18 | Building is currently only tested on Linux. Clone the repo and fetch the submodules: 19 | 20 | ``` 21 | git submodule init 22 | git submodule update 23 | ``` 24 | 25 | To build the project, run `cargo build`. 26 | `picoquic-sys` will also build the `picoquic` c-library for you (hopefully). 27 | 28 | ### Example 29 | 30 | #### Client 31 | ```rust 32 | extern crate bytes; 33 | extern crate futures; 34 | extern crate picoquic; 35 | extern crate tokio; 36 | 37 | use picoquic::{Config, Context}; 38 | 39 | use bytes::Bytes; 40 | 41 | use futures::{Future, Sink, Stream}; 42 | 43 | fn main() { 44 | let mut evt_loop = tokio::runtime::Runtime::new().unwrap(); 45 | 46 | let manifest_dir = env!("CARGO_MANIFEST_DIR"); 47 | 48 | let mut config = Config::new(); 49 | config.set_root_certificate_filename(format!("{}/examples/ca_cert.pem", manifest_dir)); 50 | 51 | let mut client = Context::new(&([0, 0, 0, 0], 0).into(), evt_loop.executor(), config).unwrap(); 52 | 53 | let mut con = evt_loop 54 | .block_on(client.new_connection(([127, 0, 0, 1], 22222).into(), "server.test")) 55 | .unwrap(); 56 | 57 | let stream = evt_loop.block_on(con.new_bidirectional_stream()).unwrap(); 58 | 59 | let stream = evt_loop 60 | .block_on(stream.send(Bytes::from("hello server"))) 61 | .unwrap(); 62 | 63 | let answer = evt_loop 64 | .block_on( 65 | stream 66 | .into_future() 67 | .map(|(m, _)| m.unwrap()) 68 | .map_err(|(e, _)| e), 69 | ) 70 | .unwrap(); 71 | 72 | println!("Got: {:?}", answer); 73 | } 74 | ``` 75 | 76 | #### Server 77 | ```rust 78 | extern crate bytes; 79 | extern crate futures; 80 | extern crate picoquic; 81 | extern crate tokio; 82 | 83 | use picoquic::{Config, Context}; 84 | 85 | use futures::{Future, Sink, Stream}; 86 | 87 | use bytes::Bytes; 88 | 89 | fn main() { 90 | let evt_loop = tokio::runtime::Runtime::new().unwrap(); 91 | 92 | let manifest_dir = env!("CARGO_MANIFEST_DIR"); 93 | 94 | let mut config = Config::new(); 95 | config.set_certificate_chain_filename(format!("{}/examples/cert.pem", manifest_dir)); 96 | config.set_private_key_filename(format!("{}/examples/key.pem", manifest_dir)); 97 | 98 | let server = Context::new(&([0, 0, 0, 0], 22222).into(), evt_loop.executor(), config).unwrap(); 99 | 100 | println!("Server listening on: {}", server.local_addr()); 101 | 102 | evt_loop.block_on_all( 103 | server 104 | .for_each(|c| { 105 | println!("New connection from: {}", c.peer_addr()); 106 | 107 | tokio::spawn( 108 | c.for_each(move |s| { 109 | // We print the received message and sent a new one, after that we collect all 110 | // remaining messages. The collect is a "hack" that prevents that the `Stream` is 111 | // dropped too early. 112 | tokio::spawn( 113 | s.into_future() 114 | .map_err(|_| ()) 115 | .and_then(|(m, s)| { 116 | println!("Got: {:?}", m); 117 | s.send(Bytes::from("hello client")).map_err(|_| ()) 118 | }) 119 | .and_then(|s| s.collect().map_err(|_| ())) 120 | .map(|_| ()), 121 | ); 122 | Ok(()) 123 | }) 124 | .map_err(|_| ()), 125 | ); 126 | 127 | Ok(()) 128 | }) 129 | ).unwrap(); 130 | } 131 | ``` 132 | 133 | ### Todo 134 | 135 | * My first crate/project that uses `failure` and I'm not happy with the current error structure :( 136 | * Support more configuration options 137 | * I currently don't check all return codes of the c functions. 138 | * Remove the TODOs from the source code 139 | 140 | ### License 141 | 142 | Licensed under either of 143 | 144 | * Apache License, Version 2.0 145 | ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) 146 | * MIT license 147 | ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) 148 | 149 | at your option. 150 | 151 | ### Contribution 152 | 153 | Unless you explicitly state otherwise, any contribution intentionally submitted 154 | for inclusion in the work by you, as defined in the Apache-2.0 license, shall be 155 | dual licensed as above, without any additional terms or conditions. 156 | 157 | License: MIT/Apache-2.0 158 | -------------------------------------------------------------------------------- /src/channel_with_error.rs: -------------------------------------------------------------------------------- 1 | use crate::error::*; 2 | 3 | use futures::{sync::mpsc, Poll, Sink, StartSend, Stream}; 4 | 5 | use std::{fmt, sync::Arc}; 6 | 7 | use parking_lot::RwLock; 8 | 9 | /// A state for storing a shared error. 10 | #[derive(Clone)] 11 | struct ErrorState { 12 | inner: Arc>>>>, 13 | } 14 | 15 | impl fmt::Debug for ErrorState { 16 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 17 | write!(f, "ErrorState") 18 | } 19 | } 20 | 21 | impl ErrorState { 22 | fn new() -> Self { 23 | Self { 24 | inner: Arc::new(RwLock::new(None)), 25 | } 26 | } 27 | /// Return the stored error. 28 | pub fn error(&self) -> Option { 29 | self.inner.read().as_ref().map(|v| v()) 30 | } 31 | 32 | /// Set the stored error function. 33 | pub fn set_error(&mut self, err_fn: T) { 34 | *self.inner.write() = Some(Box::new(err_fn)); 35 | } 36 | } 37 | 38 | /// A trait that can be used to check if a channel is closed. 39 | pub trait IsClosed { 40 | fn is_closed(&self) -> bool; 41 | } 42 | 43 | impl IsClosed for mpsc::Sender { 44 | fn is_closed(&self) -> bool { 45 | mpsc::Sender::is_closed(self) 46 | } 47 | } 48 | 49 | impl IsClosed for mpsc::UnboundedSender { 50 | fn is_closed(&self) -> bool { 51 | mpsc::UnboundedSender::is_closed(self) 52 | } 53 | } 54 | 55 | /// Error used by `Sender` to distinguish between an error set for the channel and 56 | /// a normal `futures::SendError`. 57 | pub enum SendError { 58 | Channel(Error, T), 59 | Normal(T), 60 | } 61 | 62 | /// A sender with an associated error that can be set by the receiver side. 63 | #[derive(Debug)] 64 | pub struct SenderWithError { 65 | sender: S, 66 | error_state: ErrorState, 67 | } 68 | 69 | impl Clone for SenderWithError { 70 | fn clone(&self) -> Self { 71 | Self { 72 | sender: self.sender.clone(), 73 | error_state: self.error_state.clone(), 74 | } 75 | } 76 | } 77 | 78 | impl SenderWithError { 79 | fn new(sender: S, error_state: ErrorState) -> Self { 80 | Self { 81 | sender, 82 | error_state, 83 | } 84 | } 85 | 86 | fn check_for_error(&mut self) -> Option { 87 | // If `sender` is closed, check if we got an error to propagate 88 | if self.sender.is_closed() { 89 | self.error_state.error() 90 | } else { 91 | None 92 | } 93 | } 94 | 95 | fn map_err(&mut self, e: E) -> SendError { 96 | if let Some(err) = self.check_for_error() { 97 | SendError::Channel(err, e) 98 | } else { 99 | SendError::Normal(e) 100 | } 101 | } 102 | } 103 | 104 | impl Sink for SenderWithError { 105 | type SinkItem = ::SinkItem; 106 | type SinkError = SendError<::SinkError>; 107 | 108 | fn start_send(&mut self, item: Self::SinkItem) -> StartSend { 109 | self.sender.start_send(item).map_err(|e| self.map_err(e)) 110 | } 111 | 112 | fn poll_complete(&mut self) -> Poll<(), Self::SinkError> { 113 | self.sender.poll_complete().map_err(|e| self.map_err(e)) 114 | } 115 | } 116 | 117 | /// A channel that can be closed. 118 | pub trait Close { 119 | fn close(&mut self); 120 | } 121 | 122 | impl Close for mpsc::Receiver { 123 | fn close(&mut self) { 124 | mpsc::Receiver::close(self) 125 | } 126 | } 127 | 128 | impl Close for mpsc::UnboundedReceiver { 129 | fn close(&mut self) { 130 | mpsc::UnboundedReceiver::close(self) 131 | } 132 | } 133 | 134 | /// A receiver with the ability to propagate an error to the sender. 135 | pub struct ReceiverWithError { 136 | receiver: R, 137 | error_state: ErrorState, 138 | } 139 | 140 | impl fmt::Debug for ReceiverWithError { 141 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 142 | write!(f, "ReceiverWithError") 143 | } 144 | } 145 | 146 | impl ReceiverWithError { 147 | fn new(receiver: R, error_state: ErrorState) -> Self { 148 | Self { 149 | receiver, 150 | error_state, 151 | } 152 | } 153 | 154 | /// Channel the given error to the `Sender` side. 155 | /// This will only work once, further calls of this function will just discard the error. 156 | pub fn propagate_error(&mut self, err: F) { 157 | self.error_state.set_error(err) 158 | } 159 | 160 | pub fn close(&mut self) { 161 | self.receiver.close(); 162 | } 163 | } 164 | 165 | impl Stream for ReceiverWithError { 166 | type Item = ::Item; 167 | type Error = Error; 168 | 169 | fn poll(&mut self) -> Poll, Self::Error> { 170 | self.receiver.poll().map_err(|_| ErrorKind::Unknown.into()) 171 | } 172 | } 173 | 174 | pub type UnboundedSender = SenderWithError>; 175 | pub type UnboundedReceiver = ReceiverWithError>; 176 | 177 | pub fn unbounded() -> (UnboundedSender, UnboundedReceiver) { 178 | let (sender, receiver) = mpsc::unbounded(); 179 | let error_state = ErrorState::new(); 180 | 181 | ( 182 | SenderWithError::new(sender, error_state.clone()), 183 | ReceiverWithError::new(receiver, error_state), 184 | ) 185 | } 186 | 187 | pub type Sender = SenderWithError>; 188 | pub type Receiver = ReceiverWithError>; 189 | 190 | pub fn channel(buffer: usize) -> (Sender, Receiver) { 191 | let (sender, receiver) = mpsc::channel(buffer); 192 | let error_state = ErrorState::new(); 193 | 194 | ( 195 | SenderWithError::new(sender, error_state.clone()), 196 | ReceiverWithError::new(receiver, error_state), 197 | ) 198 | } 199 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | /*! 2 | # Picoquic-rs - Tokio aware bindings of [picoquic](https://github.com/private-octopus/picoquic) 3 | [![](https://docs.rs/picoquic/badge.svg)](https://docs.rs/picoquic/) [![](https://img.shields.io/crates/v/picoquic.svg)](https://crates.io/crates/picoquic) [![](https://img.shields.io/crates/d/picoquic.png)](https://crates.io/crates/picoquic) [![Build Status](https://travis-ci.org/bkchr/picoquic-rs.png?branch=master)](https://travis-ci.org/bkchr/picoquic-rs) 4 | 5 | Picoquic is a minimalist implementation of the QUIC protocol by the IETF. The protocol is still 6 | in [development](https://github.com/quicwg) and so the implementation. 7 | 8 | * [Building](#building) 9 | * [Example](#example) 10 | * [Todo](#todo) 11 | * [License](#license) 12 | * [Contribution](#contribution) 13 | 14 | ## Building 15 | 16 | For building picoquic-rs, you need the following dependencies: 17 | * clang 18 | * openssl 19 | 20 | Building is currently only tested on Linux. To build the project, you just need to 21 | run `cargo build`. 22 | `picoquic-sys` will also build the `picoquic` c-library for you (hopefully). 23 | 24 | ## Example 25 | 26 | ### Client 27 | ```no_run 28 | extern crate bytes; 29 | extern crate futures; 30 | extern crate picoquic; 31 | extern crate tokio; 32 | 33 | use picoquic::{Config, Context}; 34 | 35 | use bytes::Bytes; 36 | 37 | use futures::{Future, Sink, Stream}; 38 | 39 | fn main() { 40 | let mut evt_loop = tokio::runtime::Runtime::new().unwrap(); 41 | 42 | let manifest_dir = env!("CARGO_MANIFEST_DIR"); 43 | 44 | let mut config = Config::new(); 45 | config.set_root_certificate_filename(format!("{}/examples/ca_cert.pem", manifest_dir)); 46 | 47 | let mut client = Context::new(&([0, 0, 0, 0], 0).into(), evt_loop.executor(), config).unwrap(); 48 | 49 | let mut con = evt_loop 50 | .block_on(client.new_connection(([127, 0, 0, 1], 22222).into(), "server.test")) 51 | .unwrap(); 52 | 53 | let stream = evt_loop.block_on(con.new_bidirectional_stream()).unwrap(); 54 | 55 | let stream = evt_loop 56 | .block_on(stream.send(Bytes::from("hello server"))) 57 | .unwrap(); 58 | 59 | let answer = evt_loop 60 | .block_on( 61 | stream 62 | .into_future() 63 | .map(|(m, _)| m.unwrap()) 64 | .map_err(|(e, _)| e), 65 | ) 66 | .unwrap(); 67 | 68 | println!("Got: {:?}", answer); 69 | } 70 | ``` 71 | 72 | ### Server 73 | ```no_run 74 | extern crate bytes; 75 | extern crate futures; 76 | extern crate picoquic; 77 | extern crate tokio; 78 | 79 | use picoquic::{Config, Context}; 80 | 81 | use futures::{Future, Sink, Stream}; 82 | 83 | use bytes::Bytes; 84 | 85 | fn main() { 86 | let evt_loop = tokio::runtime::Runtime::new().unwrap(); 87 | 88 | let manifest_dir = env!("CARGO_MANIFEST_DIR"); 89 | 90 | let mut config = Config::new(); 91 | config.set_certificate_chain_filename(format!("{}/examples/cert.pem", manifest_dir)); 92 | config.set_private_key_filename(format!("{}/examples/key.pem", manifest_dir)); 93 | 94 | let server = Context::new(&([0, 0, 0, 0], 22222).into(), evt_loop.executor(), config).unwrap(); 95 | 96 | println!("Server listening on: {}", server.local_addr()); 97 | 98 | evt_loop.block_on_all( 99 | server 100 | .for_each(|c| { 101 | println!("New connection from: {}", c.peer_addr()); 102 | 103 | tokio::spawn( 104 | c.for_each(move |s| { 105 | // We print the received message and sent a new one, after that we collect all 106 | // remaining messages. The collect is a "hack" that prevents that the `Stream` is 107 | // dropped too early. 108 | tokio::spawn( 109 | s.into_future() 110 | .map_err(|_| ()) 111 | .and_then(|(m, s)| { 112 | println!("Got: {:?}", m); 113 | s.send(Bytes::from("hello client")).map_err(|_| ()) 114 | }) 115 | .and_then(|s| s.collect().map_err(|_| ())) 116 | .map(|_| ()), 117 | ); 118 | Ok(()) 119 | }) 120 | .map_err(|_| ()), 121 | ); 122 | 123 | Ok(()) 124 | }) 125 | ).unwrap(); 126 | } 127 | ``` 128 | 129 | ## Todo 130 | 131 | * My first crate/project that uses `failure` and I'm not happy with the current error structure :( 132 | * Support more configuration options 133 | * I currently don't check all return codes of the c functions. 134 | * Remove the TODOs from the source code 135 | 136 | ## License 137 | 138 | Licensed under either of 139 | 140 | * Apache License, Version 2.0 141 | ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) 142 | * MIT license 143 | ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) 144 | 145 | at your option. 146 | 147 | ## Contribution 148 | 149 | Unless you explicitly state otherwise, any contribution intentionally submitted 150 | for inclusion in the work by you, as defined in the Apache-2.0 license, shall be 151 | dual licensed as above, without any additional terms or conditions. 152 | */ 153 | 154 | #[macro_use] 155 | extern crate futures; 156 | #[macro_use] 157 | extern crate log; 158 | 159 | #[macro_use] 160 | mod error; 161 | mod channel_with_error; 162 | mod config; 163 | mod connection; 164 | mod context; 165 | mod context_inner; 166 | mod ffi; 167 | mod stream; 168 | mod swappable_stream; 169 | mod verify_certificate; 170 | 171 | pub use self::config::{Config, FileFormat, Role}; 172 | pub use self::connection::{ 173 | Connection, Id as ConnectionId, NewStreamFuture, NewStreamHandle, Type as ConnectionType, 174 | }; 175 | pub use self::context::Context; 176 | pub use self::context_inner::{NewConnectionFuture, NewConnectionHandle}; 177 | pub use self::error::{Error, ErrorKind}; 178 | pub use self::stream::{Stream, Type as SType}; 179 | pub use self::verify_certificate::{default_verify_certificate, VerifyCertificate}; 180 | -------------------------------------------------------------------------------- /src/ffi/verify_certificate.rs: -------------------------------------------------------------------------------- 1 | use crate::error::*; 2 | use crate::ffi::{Connection, QuicCtx}; 3 | use crate::verify_certificate::VerifyCertificate; 4 | 5 | use picoquic_sys::picoquic::{ 6 | picoquic_cnx_t, picoquic_set_verify_certificate_callback, picoquic_verify_sign_cb_fn, 7 | ptls_iovec_t, PTLS_ALERT_BAD_CERTIFICATE, PTLS_ALERT_CERTIFICATE_EXPIRED, 8 | PTLS_ALERT_CERTIFICATE_REVOKED, PTLS_ALERT_CERTIFICATE_UNKNOWN, PTLS_ALERT_DECRYPT_ERROR, 9 | PTLS_ERROR_LIBRARY, PTLS_ERROR_NO_MEMORY, 10 | }; 11 | 12 | use std::mem; 13 | use std::os::raw::{c_int, c_void}; 14 | use std::slice; 15 | 16 | use openssl::error::ErrorStack; 17 | use openssl::hash::MessageDigest; 18 | use openssl::pkey::{Id, PKey, Public}; 19 | use openssl::rsa::Padding; 20 | use openssl::sign::{RsaPssSaltlen, Verifier}; 21 | use openssl::stack::Stack; 22 | use openssl::x509::X509; 23 | 24 | use openssl_sys::{X509_V_ERR_CERT_HAS_EXPIRED, X509_V_ERR_CERT_REVOKED, X509_V_ERR_OUT_OF_MEM}; 25 | 26 | pub type PubKey = PKey; 27 | 28 | /// Sets up the verify certificate callback in picoquic 29 | pub fn setup_callback(quic: &QuicCtx, handler: Box) -> Result<(), Error> { 30 | let result; 31 | unsafe { 32 | let ctx = Box::into_raw(Box::new(handler)); 33 | 34 | result = picoquic_set_verify_certificate_callback( 35 | quic.as_ptr(), 36 | Some(verify_certificate_callback), 37 | ctx as *mut c_void, 38 | Some(free_ctx), 39 | ); 40 | } 41 | 42 | if result != 0 { 43 | Err(ErrorKind::OutOfMemoryError.into()) 44 | } else { 45 | Ok(()) 46 | } 47 | } 48 | 49 | /// Will be called by picoquic to free the handler context 50 | unsafe extern "C" fn free_ctx(ctx: *mut c_void) { 51 | let _ = get_handler(ctx); 52 | } 53 | 54 | /// Will be called by picoquic to verify the signed data 55 | unsafe extern "C" fn verify_sign_callback( 56 | ctx: *mut c_void, 57 | data: ptls_iovec_t, 58 | sign: ptls_iovec_t, 59 | ) -> c_int { 60 | let pkey = get_pkey(ctx); 61 | let data = slice::from_raw_parts(data.base, data.len); 62 | let sign = slice::from_raw_parts(sign.base, sign.len); 63 | 64 | if data.is_empty() || sign.is_empty() { 65 | return 0; 66 | } 67 | 68 | let mut verifier = match Verifier::new(MessageDigest::sha256(), &pkey) { 69 | Ok(verifier) => verifier, 70 | Err(_) => return PTLS_ERROR_LIBRARY as i32, 71 | }; 72 | 73 | if pkey.id() == Id::RSA { 74 | if verifier.set_rsa_padding(Padding::PKCS1_PSS).is_err() { 75 | return PTLS_ERROR_LIBRARY as i32; 76 | } 77 | 78 | if verifier 79 | .set_rsa_pss_saltlen(RsaPssSaltlen::DIGEST_LENGTH) 80 | .is_err() 81 | { 82 | return PTLS_ERROR_LIBRARY as i32; 83 | } 84 | 85 | if verifier.set_rsa_mgf1_md(MessageDigest::sha256()).is_err() { 86 | return PTLS_ERROR_LIBRARY as i32; 87 | } 88 | } 89 | 90 | if verifier.update(data).is_err() { 91 | return PTLS_ERROR_LIBRARY as i32; 92 | } 93 | 94 | if verifier.verify(sign).unwrap_or(false) { 95 | 0 96 | } else { 97 | PTLS_ALERT_DECRYPT_ERROR as i32 98 | } 99 | } 100 | 101 | fn get_pkey(ptr: *mut c_void) -> Box { 102 | unsafe { Box::from_raw(ptr as *mut PubKey) } 103 | } 104 | 105 | /// The main verify certificate callback 106 | unsafe extern "C" fn verify_certificate_callback( 107 | ctx: *mut c_void, 108 | cnx: *mut picoquic_cnx_t, 109 | certs: *mut ptls_iovec_t, 110 | num_certs: usize, 111 | verify_sign: *mut picoquic_verify_sign_cb_fn, 112 | verify_sign_ctx: *mut *mut c_void, 113 | ) -> c_int { 114 | let mut handler = get_handler(ctx); 115 | 116 | let result = verify_certificate_callback_impl( 117 | &mut **handler, 118 | cnx, 119 | certs, 120 | num_certs, 121 | verify_sign, 122 | verify_sign_ctx, 123 | ); 124 | 125 | mem::forget(handler); 126 | 127 | result as i32 128 | } 129 | 130 | fn verify_certificate_callback_impl( 131 | handler: &mut dyn VerifyCertificate, 132 | cnx: *mut picoquic_cnx_t, 133 | certs: *mut ptls_iovec_t, 134 | num_certs: usize, 135 | verify_sign: *mut picoquic_verify_sign_cb_fn, 136 | verify_sign_ctx: *mut *mut c_void, 137 | ) -> u32 { 138 | if num_certs == 0 { 139 | return PTLS_ALERT_CERTIFICATE_UNKNOWN; 140 | } 141 | 142 | let (cert, chain) = match extract_certificates(certs, num_certs) { 143 | Ok(res) => res, 144 | Err(_) => return PTLS_ALERT_BAD_CERTIFICATE, 145 | }; 146 | 147 | let cnx = Connection::from(cnx); 148 | 149 | let id = cnx.local_id(); 150 | 151 | match handler.verify(id, cnx.con_type(), &cert, &chain) { 152 | Ok(true) => {} 153 | Ok(false) => { 154 | return PTLS_ALERT_CERTIFICATE_UNKNOWN; 155 | } 156 | Err(e) => return ssl_error_to_error_code(&e), 157 | }; 158 | 159 | // Extract the public key, as we need this public key to verify the signed data in 160 | // `verify_sign_callback`. 161 | let pkey = match cert.public_key() { 162 | Ok(pkey) => pkey, 163 | Err(e) => return ssl_error_to_error_code(&e), 164 | }; 165 | 166 | unsafe { 167 | *verify_sign = Some(verify_sign_callback); 168 | *verify_sign_ctx = Box::into_raw(Box::new(pkey)) as *mut c_void; 169 | } 170 | 171 | 0 172 | } 173 | 174 | fn get_handler(ptr: *mut c_void) -> Box> { 175 | unsafe { Box::from_raw(ptr as *mut Box) } 176 | } 177 | 178 | /// Converts a openssl error to a picotls error 179 | fn ssl_error_to_error_code(error: &ErrorStack) -> u32 { 180 | if let Some(error) = error.errors().first() { 181 | match error.code() as i32 { 182 | X509_V_ERR_OUT_OF_MEM => PTLS_ERROR_NO_MEMORY, 183 | X509_V_ERR_CERT_REVOKED => PTLS_ALERT_CERTIFICATE_REVOKED, 184 | X509_V_ERR_CERT_HAS_EXPIRED => PTLS_ALERT_CERTIFICATE_EXPIRED, 185 | _ => PTLS_ALERT_CERTIFICATE_UNKNOWN, 186 | } 187 | } else { 188 | PTLS_ALERT_CERTIFICATE_UNKNOWN 189 | } 190 | } 191 | 192 | fn extract_certificates( 193 | certs: *mut ptls_iovec_t, 194 | num_certs: usize, 195 | ) -> Result<(X509, Stack), ErrorStack> { 196 | let certs = unsafe { slice::from_raw_parts_mut(certs, num_certs) }; 197 | let cert = extract_certificate(certs[0])?; 198 | let mut chain = Stack::new()?; 199 | 200 | for cert in certs.iter().skip(1) { 201 | chain.push(extract_certificate(*cert)?)?; 202 | } 203 | 204 | Ok((cert, chain)) 205 | } 206 | 207 | fn extract_certificate(cert: ptls_iovec_t) -> Result { 208 | let data = unsafe { slice::from_raw_parts_mut(cert.base, cert.len) }; 209 | X509::from_der(data) 210 | } 211 | -------------------------------------------------------------------------------- /src/config.rs: -------------------------------------------------------------------------------- 1 | use super::VerifyCertificate; 2 | use crate::error::*; 3 | use picoquic_sys::picoquic::PICOQUIC_RESET_SECRET_SIZE; 4 | 5 | use std::path::PathBuf; 6 | use std::time::Duration; 7 | 8 | /// A role can either be `Server` or `Client`. 9 | /// The role can be used to define which side is responsible for certain tasks, like sending 10 | /// keep alive packages. 11 | #[derive(Clone, Copy, PartialEq)] 12 | pub enum Role { 13 | Server, 14 | Client, 15 | } 16 | 17 | /// The file format of a certificate/private private_key. 18 | #[derive(Clone, Copy, PartialEq)] 19 | pub enum FileFormat { 20 | PEM, 21 | DER, 22 | } 23 | 24 | /// Configuration used by `Context` to setup Picoquic. 25 | pub struct Config { 26 | /// The path to the certificate chain(PEM format). 27 | pub certificate_chain_filename: Option, 28 | /// The certificate chain in memory in the given file format. 29 | pub certificate_chain: Option<(FileFormat, Vec>)>, 30 | /// The path to the root certificate (PEM format). 31 | pub root_certificate_filename: Option, 32 | /// The root certificate in memory in the given file format. 33 | pub root_certificates: Option<(FileFormat, Vec>)>, 34 | /// The path to the private private_key(PEM format). 35 | pub private_key_filename: Option, 36 | /// The private private_key in memory in the given file format. 37 | pub private_key: Option<(FileFormat, Vec)>, 38 | /// The reset seed is used to create the stateless resets per `Connection`. 39 | pub reset_seed: Option<[u8; PICOQUIC_RESET_SECRET_SIZE as usize]>, 40 | /// The interval between keep alive packages. If the value is set to `Some(interval)`, 41 | /// each `Connection`, that matches the `keep_alive_sender` role, will send keep alive 42 | /// packages in the given `interval`. 43 | pub keep_alive_interval: Option, 44 | /// The side of a `Connection` that is responsible for sending the keep alive packages. 45 | /// Default: `Role::Client` 46 | pub keep_alive_sender: Role, 47 | /// Sets TLS client authentication on the server. 48 | /// Default: false 49 | pub client_authentication: bool, 50 | /// The handler that should verify the peer certificate in the TLS handshake. 51 | pub verify_certificate_handler: Option>, 52 | /// The default size used when creating the sending channel for a `Stream`. 53 | /// Default is 100. 54 | pub stream_send_channel_default_size: usize, 55 | } 56 | 57 | impl Config { 58 | /// Creates a new `Config`. 59 | pub fn new() -> Config { 60 | Config::default() 61 | } 62 | 63 | /// Will create a new instance by cloning another `Config`. 64 | /// The `verify_certificate_handler` will be set to `None` as it does not support to be cloned. 65 | pub fn clone_from(other: &Config) -> Config { 66 | Config { 67 | certificate_chain_filename: other.certificate_chain_filename.clone(), 68 | certificate_chain: other.certificate_chain.clone(), 69 | root_certificates: other.root_certificates.clone(), 70 | root_certificate_filename: other.root_certificate_filename.clone(), 71 | private_key_filename: other.private_key_filename.clone(), 72 | private_key: other.private_key.clone(), 73 | reset_seed: other.reset_seed, 74 | keep_alive_interval: other.keep_alive_interval, 75 | keep_alive_sender: other.keep_alive_sender, 76 | client_authentication: other.client_authentication, 77 | verify_certificate_handler: None, 78 | stream_send_channel_default_size: other.stream_send_channel_default_size, 79 | } 80 | } 81 | 82 | /// Sets the certificate chain(PEM format) filename. 83 | pub fn set_certificate_chain_filename>(&mut self, path: C) { 84 | self.certificate_chain_filename = Some(path.into()) 85 | } 86 | 87 | /// Sets the private key(PEM format) filename. 88 | pub fn set_private_key_filename>(&mut self, path: P) { 89 | self.private_key_filename = Some(path.into()) 90 | } 91 | 92 | /// Enables keep alive. 93 | pub fn enable_keep_alive(&mut self, dur: Duration) { 94 | self.keep_alive_interval = Some(dur); 95 | } 96 | 97 | /// Sets the sender for the keep alive messages. 98 | /// The default value is `Role::Client`. This value should be the same on the server and the 99 | /// client, otherwise both send continuously useless messages. 100 | pub fn set_keep_alive_sender(&mut self, role: Role) { 101 | self.keep_alive_sender = role; 102 | } 103 | 104 | /// Enables TLS client authentication on the server. 105 | pub fn enable_client_authentication(&mut self) { 106 | self.client_authentication = true; 107 | } 108 | 109 | /// Sets the handler that should verify the peer certificate in the TLS handshake. 110 | pub fn set_verify_certificate_handler(&mut self, handler: H) { 111 | self.verify_certificate_handler = Some(Box::new(handler)); 112 | } 113 | 114 | /// Sets the certificate. 115 | /// This option will overwrite `set_certificate_chain_filename`. 116 | pub fn set_certificate_chain(&mut self, certs: Vec>, format: FileFormat) { 117 | self.certificate_chain = Some((format, certs)); 118 | } 119 | 120 | /// Sets the private private_key. 121 | /// This option will overwrite `set_private_key_filename`. 122 | pub fn set_private_key(&mut self, private_key: Vec, format: FileFormat) { 123 | self.private_key = Some((format, private_key)); 124 | } 125 | 126 | /// Sets the root certificate(PEM format) filename. 127 | pub fn set_root_certificate_filename>(&mut self, path: P) { 128 | self.root_certificate_filename = Some(path.into()) 129 | } 130 | 131 | /// Sets the root certificates. 132 | /// This option will overwrite `set_root_certificate_filename`. 133 | pub fn set_root_certificates(&mut self, certificates: Vec>, format: FileFormat) { 134 | self.root_certificates = Some((format, certificates)); 135 | } 136 | 137 | /// Sets the default size of the `Stream` send channel. 138 | pub fn set_stream_send_channel_default_size(&mut self, size: usize) { 139 | self.stream_send_channel_default_size = size; 140 | } 141 | 142 | /// Verify this `Config` for common errors. 143 | pub(crate) fn verify(&self) -> Result<(), Error> { 144 | let private_key_set = self.private_key.is_some() || self.private_key_filename.is_some(); 145 | let certificate_set = 146 | self.certificate_chain.is_some() || self.certificate_chain_filename.is_some(); 147 | if private_key_set != certificate_set { 148 | bail!("Either both, private key and certificate chain need to be set or none of them!"); 149 | } 150 | 151 | fn check_path_exist(path: &Option) -> Result<(), Error> { 152 | match path { 153 | Some(ref path) if !path.exists() => bail!("File does not exist: {:?}", path), 154 | _ => Ok(()), 155 | } 156 | } 157 | 158 | check_path_exist(&self.certificate_chain_filename)?; 159 | check_path_exist(&self.root_certificate_filename)?; 160 | check_path_exist(&self.private_key_filename)?; 161 | 162 | Ok(()) 163 | } 164 | } 165 | 166 | impl Default for Config { 167 | fn default() -> Self { 168 | Config { 169 | certificate_chain_filename: None, 170 | certificate_chain: None, 171 | root_certificate_filename: None, 172 | root_certificates: None, 173 | private_key_filename: None, 174 | private_key: None, 175 | reset_seed: None, 176 | keep_alive_interval: None, 177 | keep_alive_sender: Role::Client, 178 | client_authentication: false, 179 | verify_certificate_handler: None, 180 | stream_send_channel_default_size: 100, 181 | } 182 | } 183 | } 184 | 185 | #[cfg(test)] 186 | mod tests { 187 | use super::*; 188 | 189 | #[test] 190 | #[should_panic(expected = "File does not exist")] 191 | fn non_existing_path_fails_verify() { 192 | let mut config = Config::default(); 193 | config.set_certificate_chain_filename("/does/not/exist"); 194 | config.set_private_key_filename("/does/not/exist"); 195 | config.verify().unwrap(); 196 | } 197 | 198 | #[test] 199 | #[should_panic(expected = "Either both")] 200 | fn set_private_key_and_not_certificate_fails_verify() { 201 | let mut config = Config::default(); 202 | config.set_private_key(Vec::new(), FileFormat::DER); 203 | config.verify().unwrap(); 204 | } 205 | 206 | #[test] 207 | #[should_panic(expected = "Either both")] 208 | fn set_certificate_and_not_private_key_fails_verify() { 209 | let mut config = Config::default(); 210 | config.set_certificate_chain(Vec::new(), FileFormat::DER); 211 | config.verify().unwrap(); 212 | } 213 | } 214 | -------------------------------------------------------------------------------- /src/ffi/connection.rs: -------------------------------------------------------------------------------- 1 | use super::{ 2 | quic_ctx::{ 3 | socket_addr_from_sockaddr, socket_addr_from_sockaddr_storage, MicroSeconds, QuicCtx, 4 | }, 5 | Pointer, 6 | }; 7 | use crate::connection; 8 | use crate::error::*; 9 | use crate::stream; 10 | use crate::ConnectionType; 11 | use picoquic_sys::picoquic::picoquic_get_earliest_cnx_to_wake; 12 | 13 | use picoquic_sys::picoquic::{ 14 | self, picoquic_close, picoquic_cnx_t, picoquic_create_client_cnx, picoquic_delete_cnx, 15 | picoquic_enable_keep_alive, picoquic_get_cnx_state, picoquic_get_local_addr, 16 | picoquic_get_local_cnxid, picoquic_get_local_error, picoquic_get_peer_addr, 17 | picoquic_get_remote_error, picoquic_is_client, picoquic_is_handshake_error, 18 | picoquic_prepare_packet, picoquic_quic_t, picoquic_state_enum_picoquic_state_closing, 19 | picoquic_state_enum_picoquic_state_disconnected, picoquic_val64_connection_id, 20 | PICOQUIC_ERROR_DISCONNECTED, 21 | }; 22 | 23 | use std::{ffi::CString, mem, net::SocketAddr, ptr, time::Duration}; 24 | 25 | use socket2::SockAddr; 26 | 27 | #[derive(Copy, Clone)] 28 | pub struct Connection { 29 | cnx: Pointer, 30 | } 31 | 32 | impl Connection { 33 | pub fn new( 34 | quic: &QuicCtx, 35 | server_addr: SocketAddr, 36 | current_time: u64, 37 | server_name: String, 38 | ) -> Result { 39 | assert!( 40 | !server_addr.ip().is_unspecified(), 41 | "server address must not be unspecified!" 42 | ); 43 | 44 | let server_addr = SockAddr::from(server_addr); 45 | 46 | let server_name = CString::new(server_name)?; 47 | 48 | let cnx = unsafe { 49 | picoquic_create_client_cnx( 50 | quic.as_ptr(), 51 | server_addr.as_ptr() as *mut picoquic::sockaddr, 52 | current_time, 53 | 0, 54 | server_name.as_c_str().as_ptr(), 55 | CString::new("picoquic").unwrap().as_ptr(), 56 | None, 57 | ptr::null_mut(), 58 | ) 59 | }; 60 | 61 | if cnx.is_null() { 62 | Err(ErrorKind::Unknown)?; 63 | } 64 | 65 | Ok(Connection { cnx: Pointer(cnx) }) 66 | } 67 | 68 | pub fn as_ptr(self) -> *mut picoquic_cnx_t { 69 | *self.cnx 70 | } 71 | 72 | /// Returns the peer address of this connection. 73 | pub fn peer_addr(self) -> SocketAddr { 74 | let mut addr_len = 0; 75 | let mut addr: *mut picoquic::sockaddr = ptr::null_mut(); 76 | 77 | unsafe { 78 | picoquic_get_peer_addr(*self.cnx, &mut addr, &mut addr_len); 79 | 80 | socket_addr_from_sockaddr(addr, addr_len) 81 | } 82 | } 83 | 84 | /// Returns the local address of this connection. 85 | pub fn local_addr(self) -> SocketAddr { 86 | let mut addr_len = 0; 87 | let mut addr: *mut picoquic::sockaddr = ptr::null_mut(); 88 | 89 | unsafe { 90 | picoquic_get_local_addr(*self.cnx, &mut addr, &mut addr_len); 91 | 92 | socket_addr_from_sockaddr(addr, addr_len) 93 | } 94 | } 95 | 96 | /// Prepares a `Packet`. 97 | /// The `Packet` contains any data from this connection(data from streams, ACK's, ...). 98 | /// The `Packet` will be stored in the given buffer. 99 | /// 100 | /// # Returns 101 | /// The length of the `Packet` in the buffer or `None` if the packet does not contains any data. 102 | pub fn prepare_packet( 103 | self, 104 | buffer: &mut [u8], 105 | current_time: u64, 106 | ) -> Result, Error> { 107 | let mut send_len = 0; 108 | let mut addr_len = 0; 109 | let mut addr: picoquic::sockaddr_storage = 110 | unsafe { mem::MaybeUninit::uninit().assume_init() }; 111 | let ret = unsafe { 112 | picoquic_prepare_packet( 113 | self.as_ptr(), 114 | current_time, 115 | buffer.as_mut_ptr(), 116 | buffer.len(), 117 | &mut send_len, 118 | &mut addr, 119 | &mut addr_len, 120 | ptr::null_mut(), 121 | ptr::null_mut(), 122 | ) 123 | }; 124 | 125 | if ret == PICOQUIC_ERROR_DISCONNECTED as i32 { 126 | Err(ErrorKind::Disconnected.into()) 127 | } else if ret == 0 { 128 | if send_len > 0 { 129 | Ok(Some(( 130 | send_len, 131 | socket_addr_from_sockaddr_storage(&addr, addr_len), 132 | ))) 133 | } else { 134 | Ok(None) 135 | } 136 | } else { 137 | Err(ErrorKind::Unknown.into()) 138 | } 139 | } 140 | 141 | /// Deletes the underlying C pointer! 142 | pub fn delete(self) { 143 | unsafe { 144 | picoquic_delete_cnx(*self.cnx); 145 | } 146 | } 147 | 148 | pub fn is_disconnected(self) -> bool { 149 | self.state() == picoquic_state_enum_picoquic_state_disconnected 150 | } 151 | 152 | /// Is the connection going to close? (aka in closing, draining or disconnected state) 153 | pub fn is_going_to_close(self) -> bool { 154 | self.state() >= picoquic_state_enum_picoquic_state_closing 155 | } 156 | 157 | fn state(self) -> u32 { 158 | unsafe { picoquic_get_cnx_state(*self.cnx) } 159 | } 160 | 161 | pub fn close(self) { 162 | //TODO maybe replace 0 with an appropriate error code 163 | unsafe { 164 | picoquic_close(*self.cnx, 0); 165 | } 166 | } 167 | 168 | /// Generates a new `Stream` id from the given `next_id`. The `next_id` can be incremented by 169 | /// one, after calling this function. The resulting `Stream` id depends on `is_client` and 170 | /// `stype`, as both values are encoded in the first two bits of the new id. 171 | pub(crate) fn generate_stream_id( 172 | next_id: u64, 173 | is_client: bool, 174 | stype: stream::Type, 175 | ) -> stream::Id { 176 | // Stream 0, 1, 2 and 3 are reserved. 177 | // Client first usable stream is 4, Server first usable stream is 5. 178 | // Client gets even stream ids and server gets odd stream ids. 179 | let mut id = next_id + 1; 180 | 181 | id <<= 2; 182 | 183 | if !is_client { 184 | id |= 1; 185 | } 186 | 187 | // Unidirectional sets the second bit to 1 188 | if let stream::Type::Unidirectional = stype { 189 | id |= 2; 190 | } 191 | 192 | id 193 | } 194 | 195 | pub fn enable_keep_alive(self, interval: Duration) { 196 | let interval = interval.as_micro_seconds(); 197 | unsafe { 198 | picoquic_enable_keep_alive(*self.cnx, interval); 199 | } 200 | } 201 | 202 | /// Returns the local connection id for this connection. 203 | pub fn local_id(self) -> connection::Id { 204 | unsafe { 205 | let id = picoquic_get_local_cnxid(self.as_ptr()); 206 | picoquic_val64_connection_id(id) 207 | } 208 | } 209 | 210 | /// Returns the type of this connection. 211 | pub fn con_type(self) -> ConnectionType { 212 | unsafe { 213 | if picoquic_is_client(self.as_ptr()) == 1 { 214 | ConnectionType::Outgoing 215 | } else { 216 | ConnectionType::Incoming 217 | } 218 | } 219 | } 220 | 221 | /// Checks if the connection had an error. 222 | /// The returned closure, will always construct the same error. 223 | pub fn error(self) -> Option { 224 | let error_code = unsafe { 225 | let error = picoquic_get_local_error(self.as_ptr()); 226 | if error != 0 { 227 | error 228 | } else { 229 | picoquic_get_remote_error(self.as_ptr()) 230 | } 231 | }; 232 | 233 | let is_handshake_error = unsafe { picoquic_is_handshake_error(error_code as u16) == 1 }; 234 | if error_code == 0 { 235 | None 236 | } else { 237 | Some(move || { 238 | if is_handshake_error { 239 | ErrorKind::TLSHandshakeError.into() 240 | } else { 241 | ErrorKind::Unknown.into() 242 | } 243 | }) 244 | } 245 | } 246 | } 247 | 248 | impl From<*mut picoquic_cnx_t> for Connection { 249 | fn from(cnx: *mut picoquic_cnx_t) -> Connection { 250 | Connection { cnx: Pointer(cnx) } 251 | } 252 | } 253 | 254 | /// Connection iterator ordered by their next wake up time. 255 | pub struct ConnectionIter { 256 | current_time: u64, 257 | context: *mut picoquic_quic_t, 258 | } 259 | 260 | impl ConnectionIter { 261 | pub fn new(quic: *mut picoquic_quic_t, current_time: u64) -> ConnectionIter { 262 | ConnectionIter { 263 | current_time, 264 | context: quic, 265 | } 266 | } 267 | } 268 | 269 | impl Iterator for ConnectionIter { 270 | type Item = Connection; 271 | 272 | fn next(&mut self) -> Option { 273 | unsafe { 274 | let next = picoquic_get_earliest_cnx_to_wake(self.context, self.current_time); 275 | if next.is_null() { 276 | None 277 | } else { 278 | Some(next.into()) 279 | } 280 | } 281 | } 282 | } 283 | 284 | #[cfg(test)] 285 | mod tests { 286 | use super::*; 287 | 288 | #[test] 289 | fn client_bidirectional_stream_id_generation() { 290 | assert_eq!( 291 | 4, 292 | Connection::generate_stream_id(0, true, stream::Type::Bidirectional) 293 | ); 294 | assert_eq!( 295 | 8, 296 | Connection::generate_stream_id(1, true, stream::Type::Bidirectional) 297 | ); 298 | assert_eq!( 299 | 12, 300 | Connection::generate_stream_id(2, true, stream::Type::Bidirectional) 301 | ); 302 | } 303 | 304 | #[test] 305 | fn client_unidirectional_stream_id_generation() { 306 | assert_eq!( 307 | 6, 308 | Connection::generate_stream_id(0, true, stream::Type::Unidirectional) 309 | ); 310 | assert_eq!( 311 | 10, 312 | Connection::generate_stream_id(1, true, stream::Type::Unidirectional) 313 | ); 314 | assert_eq!( 315 | 14, 316 | Connection::generate_stream_id(2, true, stream::Type::Unidirectional) 317 | ); 318 | } 319 | 320 | #[test] 321 | fn server_bidirectional_stream_id_generation() { 322 | assert_eq!( 323 | 5, 324 | Connection::generate_stream_id(0, false, stream::Type::Bidirectional) 325 | ); 326 | assert_eq!( 327 | 9, 328 | Connection::generate_stream_id(1, false, stream::Type::Bidirectional) 329 | ); 330 | assert_eq!( 331 | 13, 332 | Connection::generate_stream_id(2, false, stream::Type::Bidirectional) 333 | ); 334 | } 335 | 336 | #[test] 337 | fn server_unidirectional_stream_id_generation() { 338 | assert_eq!( 339 | 7, 340 | Connection::generate_stream_id(0, false, stream::Type::Unidirectional) 341 | ); 342 | assert_eq!( 343 | 11, 344 | Connection::generate_stream_id(1, false, stream::Type::Unidirectional) 345 | ); 346 | assert_eq!( 347 | 15, 348 | Connection::generate_stream_id(2, false, stream::Type::Unidirectional) 349 | ); 350 | } 351 | 352 | #[test] 353 | #[should_panic(expected = "server address must not be unspecified!")] 354 | fn do_not_accept_unspecified_ip_address() { 355 | let _ = Connection::new( 356 | &QuicCtx::dummy(), 357 | ([0, 0, 0, 0], 12345).into(), 358 | 0, 359 | "server".into(), 360 | ); 361 | } 362 | } 363 | -------------------------------------------------------------------------------- /src/ffi/quic_ctx.rs: -------------------------------------------------------------------------------- 1 | use super::{connection::ConnectionIter, stateless_packet::StatelessPacketIter, Pointer}; 2 | use crate::config::{Config, FileFormat}; 3 | use crate::error::*; 4 | use crate::ffi::verify_certificate; 5 | 6 | use picoquic_sys::picoquic::{ 7 | self, picoquic_create, picoquic_current_time, picoquic_free, picoquic_get_next_wake_delay, 8 | picoquic_incoming_packet, picoquic_quic_t, picoquic_set_client_authentication, 9 | picoquic_set_tls_certificate_chain, picoquic_set_tls_key, picoquic_set_tls_root_certificates, 10 | picoquic_stream_data_cb_fn, ptls_iovec_t, 11 | }; 12 | 13 | use std::{ 14 | ffi::CString, 15 | mem, 16 | net::SocketAddr, 17 | os::raw::{c_char, c_void}, 18 | path::PathBuf, 19 | ptr, 20 | time::{Duration, Instant}, 21 | }; 22 | 23 | use socket2::SockAddr; 24 | 25 | use libc; 26 | 27 | use openssl::pkey::PKey; 28 | use openssl::x509::X509; 29 | 30 | fn create_cstring(path: Option) -> Result, Error> { 31 | match path { 32 | Some(p) => { 33 | let string = match p.into_os_string().into_string() { 34 | Ok(string) => string, 35 | Err(_) => return Err(ErrorKind::NoneUnicode.into()), 36 | }; 37 | Ok(Some(CString::new(string)?)) 38 | } 39 | None => Ok(None), 40 | } 41 | } 42 | 43 | fn c_str_or_null(string: &Option) -> *const c_char { 44 | string 45 | .as_ref() 46 | .map(|v| v.as_ptr()) 47 | .unwrap_or_else(ptr::null) 48 | } 49 | 50 | pub struct QuicCtx { 51 | quic: Pointer, 52 | max_delay: Duration, 53 | } 54 | 55 | impl QuicCtx { 56 | pub fn new( 57 | mut config: Config, 58 | default_ctx: *mut c_void, 59 | default_callback: picoquic_stream_data_cb_fn, 60 | ) -> Result { 61 | // The number of buckets that picoquic will allocate for connections 62 | // The buckets itself are a linked list 63 | let connection_buckets = 16; 64 | 65 | let cert_filename = create_cstring(config.certificate_chain_filename)?; 66 | let key_filename = create_cstring(config.private_key_filename)?; 67 | let root_cert_filename = create_cstring(config.root_certificate_filename)?; 68 | 69 | let reset_seed = config 70 | .reset_seed 71 | .as_mut() 72 | .map(|v| v.as_mut_ptr()) 73 | .unwrap_or_else(ptr::null_mut); 74 | 75 | let quic = unsafe { 76 | picoquic_create( 77 | connection_buckets, 78 | c_str_or_null(&cert_filename), 79 | c_str_or_null(&key_filename), 80 | c_str_or_null(&root_cert_filename), 81 | ptr::null(), 82 | default_callback, 83 | default_ctx, 84 | None, 85 | ptr::null_mut(), 86 | reset_seed, 87 | picoquic_current_time(), 88 | ptr::null_mut(), 89 | ptr::null(), 90 | ptr::null(), 91 | 0, 92 | ) 93 | }; 94 | assert!(!quic.is_null()); 95 | 96 | let mut quic = QuicCtx { 97 | quic: Pointer(quic), 98 | max_delay: Duration::from_secs(10), 99 | }; 100 | 101 | if config.client_authentication { 102 | unsafe { 103 | picoquic_set_client_authentication(quic.as_ptr(), 1); 104 | } 105 | } 106 | 107 | if let Some((format, chain)) = config.certificate_chain { 108 | quic.set_tls_certificate_chain(chain, format)?; 109 | } 110 | 111 | if let Some((format, key)) = config.private_key { 112 | quic.set_tls_private_key(key, format)?; 113 | } 114 | 115 | if let Some((format, certs)) = config.root_certificates { 116 | quic.set_tls_root_certificates(certs, format)?; 117 | } 118 | 119 | if let Some(handler) = config.verify_certificate_handler.take() { 120 | verify_certificate::setup_callback(&quic, handler)?; 121 | } 122 | 123 | Ok(quic) 124 | } 125 | 126 | /// Creates a dummy instance, that uses a `NULL` pointer for the quic context. 127 | /// This function must only be used in tests! 128 | #[doc(hidden)] 129 | #[cfg(test)] 130 | pub fn dummy() -> QuicCtx { 131 | QuicCtx { 132 | quic: Pointer(ptr::null_mut()), 133 | max_delay: Duration::from_secs(10), 134 | } 135 | } 136 | 137 | pub fn as_ptr(&self) -> *mut picoquic_quic_t { 138 | *self.quic 139 | } 140 | 141 | /// Returns an iterator over all connections, ordered by their next wake up time. 142 | pub fn ordered_connection_iter(&self, current_time: u64) -> ConnectionIter { 143 | ConnectionIter::new(*self.quic, current_time) 144 | } 145 | 146 | pub fn incoming_data( 147 | &mut self, 148 | buf: &mut [u8], 149 | addr_to: SocketAddr, 150 | addr_from: SocketAddr, 151 | current_time: u64, 152 | ) { 153 | let addr_to = SockAddr::from(addr_to); 154 | let addr_from = SockAddr::from(addr_from); 155 | 156 | let ret = unsafe { 157 | picoquic_incoming_packet( 158 | *self.quic, 159 | buf.as_mut_ptr(), 160 | buf.len() as usize, 161 | addr_from.as_ptr() as *mut picoquic::sockaddr, 162 | addr_to.as_ptr() as *mut picoquic::sockaddr, 163 | // as long as we only support one udp socket, we don't need to change this index 164 | 0, 165 | // TODO: Find a way to implement ECN 166 | 0, 167 | current_time, 168 | ) 169 | }; 170 | 171 | if ret != 0 { 172 | error!("`picoquic_incoming_packet` returned: {}", ret); 173 | } 174 | } 175 | 176 | pub fn stateless_packet_iter(&self) -> StatelessPacketIter<'_> { 177 | StatelessPacketIter::new(*self.quic) 178 | } 179 | 180 | /// Returns the next time point at which Picoquic needs to get called again. However, it is 181 | /// possible to call Picoquic before, e.g. when new data arrives or the application wants to 182 | /// send new data. The time point is absolute. 183 | /// 184 | /// # Returns 185 | /// Some(_) is the next latest time Picoquic wants to get called again. None intends that 186 | /// Picoquic wants to get called again instantly. 187 | pub fn get_next_wake_up_time(&self, current_time: u64) -> Option { 188 | let max_delay = self.max_delay.as_micro_seconds() as i64; 189 | let wake_up = unsafe { picoquic_get_next_wake_delay(*self.quic, current_time, max_delay) }; 190 | 191 | if wake_up == 0 { 192 | None 193 | } else { 194 | // TODO: maybe we need to use current_time here. 195 | Some(Instant::now() + Duration::from_micro_seconds(wake_up as u64)) 196 | } 197 | } 198 | 199 | /// Returns the current time in micro seconds for Picoquic. 200 | pub fn get_current_time(&self) -> u64 { 201 | unsafe { picoquic_current_time() } 202 | } 203 | 204 | /// Sets the tls certificate chain. 205 | fn set_tls_certificate_chain( 206 | &mut self, 207 | chain: Vec>, 208 | format: FileFormat, 209 | ) -> Result<(), Error> { 210 | let (certs_ptr, len) = make_certs_iovec(chain, format)?; 211 | 212 | unsafe { 213 | picoquic_set_tls_certificate_chain(self.as_ptr(), certs_ptr, len); 214 | } 215 | 216 | Ok(()) 217 | } 218 | 219 | /// Sets the tls root certificates. 220 | fn set_tls_root_certificates( 221 | &mut self, 222 | certs: Vec>, 223 | format: FileFormat, 224 | ) -> Result<(), Error> { 225 | let (certs_ptr, len) = make_certs_iovec(certs, format)?; 226 | 227 | let res = unsafe { picoquic_set_tls_root_certificates(self.as_ptr(), certs_ptr, len) }; 228 | 229 | if res == -1 { 230 | bail!("Error at loading a root certificate") 231 | } else if res == -2 { 232 | bail!("Error at adding a root certificate, maybe a duplicate?") 233 | } else { 234 | Ok(()) 235 | } 236 | } 237 | 238 | /// Sets the tls private key. 239 | fn set_tls_private_key(&mut self, key: Vec, format: FileFormat) -> Result<(), Error> { 240 | let mut key = match format { 241 | FileFormat::DER => key, 242 | FileFormat::PEM => PKey::private_key_from_pem(&key)?.private_key_to_der()?, 243 | }; 244 | 245 | let len = key.len(); 246 | let key_ptr = key.as_mut_ptr(); 247 | 248 | unsafe { 249 | let res = picoquic_set_tls_key(self.as_ptr(), key_ptr, len); 250 | 251 | if res == 0 { 252 | Ok(()) 253 | } else { 254 | Err(ErrorKind::Unknown.into()) 255 | } 256 | } 257 | } 258 | } 259 | 260 | impl Drop for QuicCtx { 261 | fn drop(&mut self) { 262 | unsafe { 263 | picoquic_free(*self.quic); 264 | } 265 | } 266 | } 267 | 268 | fn make_certs_iovec( 269 | certs: Vec>, 270 | format: FileFormat, 271 | ) -> Result<(*mut ptls_iovec_t, usize), Error> { 272 | let certs = match format { 273 | FileFormat::DER => certs, 274 | FileFormat::PEM => { 275 | let mut res = Vec::with_capacity(certs.len()); 276 | for cert in certs { 277 | res.push(X509::from_pem(&cert)?.to_der()?); 278 | } 279 | res 280 | } 281 | }; 282 | 283 | let mut certs = certs 284 | .into_iter() 285 | .map(|mut cert| { 286 | let len = cert.len(); 287 | let base = cert.as_mut_ptr(); 288 | mem::forget(cert); 289 | 290 | ptls_iovec_t { len, base } 291 | }) 292 | .collect::>(); 293 | 294 | let len = certs.len(); 295 | let certs_ptr = certs.as_mut_ptr(); 296 | mem::forget(certs); 297 | 298 | Ok((certs_ptr, len)) 299 | } 300 | 301 | pub fn socket_addr_from_sockaddr(sock_addr: *mut picoquic::sockaddr, sock_len: i32) -> SocketAddr { 302 | let addr = 303 | unsafe { SockAddr::from_raw_parts(sock_addr as *const libc::sockaddr, sock_len as u32) }; 304 | 305 | addr.as_inet() 306 | .map(Into::into) 307 | .or_else(|| addr.as_inet6().map(Into::into)) 308 | .unwrap_or_else(|| panic!("Neither ipv4 nor ipv6? {:?} {}", sock_addr, sock_len)) 309 | } 310 | 311 | pub fn socket_addr_from_sockaddr_storage( 312 | sock_addr_storge: *const picoquic::sockaddr_storage, 313 | sock_len: i32, 314 | ) -> SocketAddr { 315 | socket_addr_from_sockaddr(sock_addr_storge as *mut picoquic::sockaddr, sock_len) 316 | } 317 | 318 | pub trait MicroSeconds { 319 | fn from_micro_seconds(micros: u64) -> Self; 320 | fn as_micro_seconds(&self) -> u64; 321 | } 322 | 323 | impl MicroSeconds for Duration { 324 | fn from_micro_seconds(micros: u64) -> Duration { 325 | let secs = micros / 1_000_000; 326 | let nanos = micros % 1_000_000 * 1000; 327 | 328 | Duration::new(secs, nanos as u32) 329 | } 330 | 331 | fn as_micro_seconds(&self) -> u64 { 332 | self.as_secs() * 1_000_000 + u64::from(self.subsec_nanos()) / 1000 333 | } 334 | } 335 | 336 | #[cfg(test)] 337 | mod tests { 338 | use super::*; 339 | 340 | #[test] 341 | fn from_micro_seconds() { 342 | assert_eq!( 343 | Duration::from_secs(1), 344 | Duration::from_micro_seconds(1_000_000) 345 | ); 346 | assert_eq!(Duration::new(0, 1000), Duration::from_micro_seconds(1)); 347 | assert_eq!( 348 | Duration::new(1, 5000), 349 | Duration::from_micro_seconds(1_000_005) 350 | ); 351 | assert_eq!(Duration::new(0, 500_000), Duration::from_micro_seconds(500)); 352 | } 353 | 354 | #[test] 355 | fn as_micro_seconds() { 356 | assert_eq!(Duration::from_secs(1).as_micro_seconds(), 1_000_000); 357 | assert_eq!(Duration::new(0, 1000).as_micro_seconds(), 1); 358 | assert_eq!(Duration::new(1, 5000).as_micro_seconds(), 1_000_005); 359 | assert_eq!(Duration::new(0, 500_000).as_micro_seconds(), 500); 360 | } 361 | } 362 | -------------------------------------------------------------------------------- /src/context_inner.rs: -------------------------------------------------------------------------------- 1 | use crate::config::{Config, Role}; 2 | use crate::connection::{self, Connection}; 3 | use crate::error::*; 4 | use crate::ffi::{self, QuicCtx}; 5 | use crate::stream; 6 | 7 | use picoquic_sys::picoquic::{ 8 | picoquic_call_back_event_t, picoquic_cnx_t, PICOQUIC_MAX_PACKET_SIZE, 9 | }; 10 | 11 | use std::{ 12 | io, mem, 13 | net::SocketAddr, 14 | os::raw::c_void, 15 | sync::{Arc, Mutex}, 16 | time::{Duration, Instant}, 17 | }; 18 | 19 | use tokio_timer::Delay; 20 | use tokio_udp::UdpSocket; 21 | 22 | use futures::{ 23 | sync::{ 24 | mpsc::{unbounded, UnboundedReceiver, UnboundedSender}, 25 | oneshot, 26 | }, 27 | task, 28 | Async::{NotReady, Ready}, 29 | Future, Poll, Stream, 30 | }; 31 | 32 | type NewConnectionMsg = ( 33 | SocketAddr, 34 | String, 35 | oneshot::Sender>, 36 | ); 37 | 38 | pub struct ContextInner { 39 | socket: UdpSocket, 40 | context: Arc>, 41 | quic: QuicCtx, 42 | /// Temporary buffer used for receiving and sending 43 | buffer: Vec, 44 | /// Data in the buffer that was not send, because the socket was full. 45 | not_send_length: Option<(usize, SocketAddr)>, 46 | /// Picoquic requires to be woken up to handle resend, 47 | /// drop of connections(because of inactivity), etc.. 48 | timer: Delay, 49 | recv_connect: UnboundedReceiver, 50 | /// The keep alive interval for client connections 51 | client_keep_alive_interval: Option, 52 | close_handle: Option>, 53 | stream_send_channel_default_size: usize, 54 | } 55 | 56 | impl ContextInner { 57 | pub fn new( 58 | listen_address: &SocketAddr, 59 | config: Config, 60 | ) -> Result< 61 | ( 62 | ContextInner, 63 | UnboundedReceiver, 64 | NewConnectionHandle, 65 | oneshot::Receiver<()>, 66 | ), 67 | Error, 68 | > { 69 | let stream_send_channel_default_size = config.stream_send_channel_default_size; 70 | let (client_keep_alive_interval, server_keep_alive_interval) = 71 | match config.keep_alive_sender { 72 | Role::Client => (config.keep_alive_interval, None), 73 | Role::Server => (None, config.keep_alive_interval), 74 | }; 75 | 76 | let (send, recv) = unbounded(); 77 | let (context, c_ctx) = CContext::new( 78 | send, 79 | server_keep_alive_interval, 80 | stream_send_channel_default_size, 81 | ); 82 | 83 | let quic = QuicCtx::new(config, c_ctx, Some(new_connection_callback))?; 84 | 85 | let (send_connect, recv_connect) = unbounded(); 86 | let connect = NewConnectionHandle { send: send_connect }; 87 | let (close_handle_send, close_handle) = oneshot::channel(); 88 | 89 | Ok(( 90 | ContextInner { 91 | socket: UdpSocket::bind(listen_address).context(ErrorKind::NetworkError)?, 92 | context, 93 | quic, 94 | buffer: vec![0; PICOQUIC_MAX_PACKET_SIZE as usize], 95 | timer: Delay::new(Instant::now() + Duration::from_secs(10)), 96 | recv_connect, 97 | client_keep_alive_interval, 98 | close_handle: Some(close_handle_send), 99 | not_send_length: None, 100 | stream_send_channel_default_size, 101 | }, 102 | recv, 103 | connect, 104 | close_handle, 105 | )) 106 | } 107 | 108 | pub fn local_addr(&self) -> SocketAddr { 109 | self.socket.local_addr().unwrap() 110 | } 111 | 112 | /// Check if we should create a new connection 113 | fn check_for_new_connection_request(&mut self, current_time: u64) { 114 | loop { 115 | match self.recv_connect.poll() { 116 | Err(_) | Ok(NotReady) | Ok(Ready(None)) => break, 117 | Ok(Ready(Some((addr, server_name, sender)))) => { 118 | let ctx = match Connection::create( 119 | &self.quic, 120 | addr, 121 | self.local_addr(), 122 | server_name, 123 | current_time, 124 | self.client_keep_alive_interval, 125 | sender, 126 | self.stream_send_channel_default_size, 127 | ) { 128 | Ok(r) => r, 129 | Err(e) => { 130 | error!("could not create new connection: {:?}", e); 131 | continue; 132 | } 133 | }; 134 | 135 | self.context.lock().unwrap().connections.push(ctx); 136 | } 137 | } 138 | } 139 | } 140 | 141 | /// Send the data in `self.buffer`. 142 | /// Returns true if the data could be send. 143 | fn send_data_in_buffer(&mut self, len: usize, addr: SocketAddr) -> bool { 144 | match self.socket.poll_send_to(&self.buffer[..len], &addr) { 145 | Ok(NotReady) => { 146 | self.not_send_length = Some((len, addr)); 147 | trace!("Socket is full and {} bytes was not send, yet!", len); 148 | false 149 | } 150 | _ => true, 151 | } 152 | } 153 | 154 | /// Iterates over all connections for data that is ready and sends it. 155 | fn send_connection_packets(&mut self, current_time: u64) { 156 | if let Some((len, addr)) = self.not_send_length.take() { 157 | if !self.send_data_in_buffer(len, addr) { 158 | return; 159 | } 160 | } 161 | 162 | let itr = self.quic.ordered_connection_iter(current_time); 163 | 164 | for con in itr { 165 | if con.is_disconnected() { 166 | con.delete(); 167 | break; 168 | } else { 169 | match con.prepare_packet(&mut self.buffer, current_time) { 170 | Ok(Some((len, addr))) => { 171 | if !self.send_data_in_buffer(len, addr) { 172 | return; 173 | } 174 | } 175 | Ok(None) => {} 176 | Err(e) => { 177 | debug!("error while sending connections packets: {:?}", e); 178 | } 179 | }; 180 | } 181 | } 182 | } 183 | 184 | /// Checks the `UdpSocket` for incoming data 185 | fn check_for_incoming_data(&mut self, current_time: u64) { 186 | fn wrapper( 187 | buf: &mut [u8], 188 | socket: &mut UdpSocket, 189 | quic: &mut QuicCtx, 190 | current_time: u64, 191 | ) -> Poll, io::Error> { 192 | loop { 193 | let (len, addr) = try_ready!(socket.poll_recv_from(buf)); 194 | quic.incoming_data( 195 | &mut buf[..len], 196 | socket.local_addr().unwrap(), 197 | addr, 198 | current_time, 199 | ); 200 | } 201 | } 202 | 203 | let _ = wrapper( 204 | &mut self.buffer, 205 | &mut self.socket, 206 | &mut self.quic, 207 | current_time, 208 | ); 209 | } 210 | 211 | fn send_stateless_packets(&mut self) -> Poll<(), Error> { 212 | let itr = self.quic.stateless_packet_iter(); 213 | 214 | for packet in itr { 215 | try_ready!(self 216 | .socket 217 | .poll_send_to(packet.get_data(), &packet.get_peer_addr())); 218 | } 219 | 220 | Ok(Ready(())) 221 | } 222 | 223 | /// Resets the timer to fire next at the given time. 224 | /// Returns true if polling the timer returned `NotReady`, otherwise false. 225 | fn reset_timer(&mut self, at: Instant) -> bool { 226 | self.timer.reset(at); 227 | // Poll the timer once, to register the current task to be woken up when the 228 | // timer finishes. 229 | self.timer.poll().map(|v| v.is_not_ready()).unwrap_or(false) 230 | } 231 | 232 | fn context_dropped(&mut self) -> bool { 233 | self.close_handle 234 | .as_mut() 235 | .map(|h| match h.poll_cancel() { 236 | Ok(Ready(_)) | Err(_) => true, 237 | Ok(NotReady) => false, 238 | }) 239 | .unwrap_or(true) 240 | } 241 | } 242 | 243 | impl Drop for ContextInner { 244 | fn drop(&mut self) { 245 | self.close_handle.take().map(|h| h.send(())); 246 | } 247 | } 248 | 249 | impl Future for ContextInner { 250 | type Item = (); 251 | type Error = (); 252 | 253 | fn poll(&mut self) -> Poll { 254 | let mut loops_without_sleep = 0; 255 | // The maximum number of times, we are allowed to loop without returning from this future. 256 | // In some circumstances this loop runs forever(Picoquic always return `wake_time = 0`) 257 | // or the overlying application layer wants to send a lot of data. If we reach the maximum 258 | // loop count, we queue the current task to be woken up again and return `Ok(NotReady)`. 259 | let max_loops_without_sleep = 50; 260 | 261 | loop { 262 | // This checks all connection contexts if there is data that needs to be send. 263 | // We do this before acquiring the current time, to make sure that we send the data 264 | // in this loop (if permitted). 265 | assert!(self.context.lock().unwrap().poll().is_ok()); 266 | 267 | let current_time = self.quic.get_current_time(); 268 | 269 | if self.context_dropped() { 270 | trace!("`Context` dropped, will end `ContextInner`."); 271 | return Ok(Ready(())); 272 | } 273 | 274 | self.check_for_new_connection_request(current_time); 275 | 276 | self.check_for_incoming_data(current_time); 277 | 278 | let _ = self.send_stateless_packets(); 279 | 280 | // All data that was send by the connection contexts, is collected to `Packet`'s per 281 | // connection and is send via the `UdpSocket`. 282 | self.send_connection_packets(current_time); 283 | 284 | let next_wake = self.quic.get_next_wake_up_time(current_time); 285 | 286 | if loops_without_sleep >= max_loops_without_sleep { 287 | task::current().notify(); 288 | return Ok(NotReady); 289 | } else if let Some(next_wake) = next_wake { 290 | if !self.reset_timer(next_wake) { 291 | // It can happen that the timer fires instantly, because the given `next_wake` 292 | // time point wasn't far enough in the future or the system is under high load, 293 | // etc.... So, we just execute the loop another time. 294 | loops_without_sleep += 1; 295 | } else { 296 | return Ok(NotReady); 297 | } 298 | } else { 299 | loops_without_sleep += 1; 300 | } 301 | } 302 | } 303 | } 304 | 305 | /// The callback context that is given as `ctx` argument to `new_connection_callback`. 306 | struct CContext { 307 | connections: Vec>>, 308 | send_con: UnboundedSender, 309 | server_keep_alive_interval: Option, 310 | stream_send_channel_default_size: usize, 311 | } 312 | 313 | impl CContext { 314 | fn new( 315 | send_con: UnboundedSender, 316 | server_keep_alive_interval: Option, 317 | stream_send_channel_default_size: usize, 318 | ) -> (Arc>, *mut c_void) { 319 | let ctx = Arc::new(Mutex::new(CContext { 320 | connections: Vec::new(), 321 | send_con, 322 | server_keep_alive_interval, 323 | stream_send_channel_default_size, 324 | })); 325 | 326 | let c_ctx = Arc::into_raw(ctx.clone()) as *mut c_void; 327 | 328 | assert_eq!(2, Arc::strong_count(&ctx)); 329 | 330 | (ctx, c_ctx) 331 | } 332 | 333 | fn new_connection(&mut self, con: Connection, ctx: Arc>) { 334 | self.connections.push(ctx); 335 | let _ = self.send_con.unbounded_send(con); 336 | } 337 | } 338 | 339 | impl Future for CContext { 340 | type Item = (); 341 | type Error = (); 342 | 343 | fn poll(&mut self) -> Poll { 344 | self.connections.retain(|c| { 345 | c.lock() 346 | .unwrap() 347 | .poll() 348 | .map(|v| v.is_not_ready()) 349 | .unwrap_or(false) 350 | }); 351 | Ok(NotReady) 352 | } 353 | } 354 | 355 | fn get_context(ctx: *mut c_void) -> Arc> { 356 | unsafe { Arc::from_raw(ctx as *mut Mutex) } 357 | } 358 | 359 | unsafe extern "C" fn new_connection_callback( 360 | cnx: *mut picoquic_cnx_t, 361 | stream_id: stream::Id, 362 | bytes: *mut u8, 363 | length: usize, 364 | event: picoquic_call_back_event_t, 365 | ctx: *mut c_void, 366 | _: *mut c_void, 367 | ) -> i32 { 368 | assert!(!ctx.is_null()); 369 | 370 | // early out, if the connection is already going to be closed, we don't need to handle it. 371 | if ffi::Connection::from(cnx).is_going_to_close() { 372 | return 0; 373 | } 374 | 375 | let ctx = get_context(ctx); 376 | { 377 | let mut ctx_locked = ctx.lock().unwrap(); 378 | 379 | let (con, con_ctx) = Connection::from_incoming( 380 | cnx, 381 | stream_id, 382 | bytes, 383 | length, 384 | event, 385 | ctx_locked.server_keep_alive_interval, 386 | ctx_locked.stream_send_channel_default_size, 387 | ); 388 | 389 | ctx_locked.new_connection(con, con_ctx); 390 | } 391 | 392 | mem::forget(ctx); 393 | 0 394 | } 395 | 396 | #[derive(Clone)] 397 | pub struct NewConnectionHandle { 398 | send: UnboundedSender, 399 | } 400 | 401 | impl NewConnectionHandle { 402 | /// Creates a new connection to the given server. 403 | /// 404 | /// addr - The address of the server. 405 | /// server_name - The name of the server that will be used by TLS to verify the certificate. 406 | pub fn new_connection>( 407 | &mut self, 408 | addr: SocketAddr, 409 | server_name: T, 410 | ) -> NewConnectionFuture { 411 | let (sender, recv) = oneshot::channel(); 412 | 413 | let _ = self.send.unbounded_send((addr, server_name.into(), sender)); 414 | 415 | NewConnectionFuture { recv } 416 | } 417 | } 418 | 419 | pub struct NewConnectionFuture { 420 | recv: oneshot::Receiver>, 421 | } 422 | 423 | impl Future for NewConnectionFuture { 424 | type Item = Connection; 425 | type Error = Error; 426 | 427 | fn poll(&mut self) -> Poll { 428 | try_ready!(self.recv.poll()).map(Ready) 429 | } 430 | } 431 | -------------------------------------------------------------------------------- /src/stream.rs: -------------------------------------------------------------------------------- 1 | use crate::channel_with_error::{ 2 | channel as channel_with_error, Receiver as ReceiverWithError, SendError, 3 | Sender as SenderWithError, 4 | }; 5 | use crate::error::*; 6 | use crate::ffi; 7 | use crate::swappable_stream::SwappableStream; 8 | use picoquic_sys::picoquic::{ 9 | self, picoquic_call_back_event_t, picoquic_mark_active_stream, 10 | picoquic_provide_stream_data_buffer, picoquic_reset_stream, picoquic_stop_sending, 11 | }; 12 | 13 | use bytes::{Bytes, BytesMut}; 14 | 15 | use futures::{ 16 | sync::mpsc::{unbounded, UnboundedReceiver, UnboundedSender}, 17 | Async::{NotReady, Ready}, 18 | Future, Poll, Sink, StartSend, Stream as FStream, 19 | }; 20 | 21 | use std::{cmp, net::SocketAddr, ptr, slice}; 22 | 23 | use smallvec::SmallVec; 24 | 25 | pub type Id = u64; 26 | 27 | /// A `Message` is used by the `Stream` to propagate information from the peer or to send 28 | /// information to the peer. 29 | #[derive(Debug)] 30 | enum Message { 31 | /// Close the `Stream`. 32 | Close, 33 | /// Recv data. 34 | RecvData(BytesMut), 35 | /// An error occurred. 36 | Error(Error), 37 | /// Reset the `Stream`. 38 | Reset, 39 | /// Swap the `send_data` receiver. 40 | /// 41 | /// This also carries the old `sender` as this one is not allowed to be dropped, before we set 42 | /// the new receiver as swappable. 43 | SwapSendData((ReceiverWithError, SenderWithError)), 44 | } 45 | 46 | /// A `Stream` can either be unidirectional or bidirectional. 47 | #[derive(Copy, Clone)] 48 | pub enum Type { 49 | Unidirectional, 50 | Bidirectional, 51 | } 52 | 53 | /// Create send and receive data channel. 54 | /// 55 | /// If the given `Stream` id is unidirectional, `(None, None)` is returned. 56 | fn create_send_and_recv_data( 57 | id: Id, 58 | client_con: bool, 59 | size: usize, 60 | ) -> ( 61 | Option>, 62 | Option>, 63 | ) { 64 | if is_unidirectional(id) && !is_unidirectional_send_allowed(id, client_con) { 65 | (None, None) 66 | } else { 67 | let (sender, receiver) = channel_with_error(size); 68 | (Some(sender), Some(receiver)) 69 | } 70 | } 71 | 72 | /// A `Stream` is part of a `Connection`. A `Connection` can consists of multiple `Stream`s. 73 | /// Each `Stream` is a new channel over the `Connection` to the Peer. All traffic of a `Stream` 74 | /// is always unique for each `Stream`. 75 | /// The `Stream` needs to be polled, to get notified about a new `Message`. 76 | #[derive(Debug)] 77 | pub struct Stream { 78 | recv_msg: UnboundedReceiver, 79 | control_msg: UnboundedSender, 80 | send_data: Option>, 81 | id: Id, 82 | peer_addr: SocketAddr, 83 | local_addr: SocketAddr, 84 | stream_reset: bool, 85 | } 86 | 87 | impl Stream { 88 | pub(crate) fn new( 89 | id: Id, 90 | cnx: ffi::Connection, 91 | local_addr: SocketAddr, 92 | is_client_con: bool, 93 | send_channel_default_size: usize, 94 | ) -> (Stream, Context) { 95 | let (recv_msg, recv_send) = unbounded(); 96 | let (control_msg, recv_control) = unbounded(); 97 | let (send_data, recv_data) = 98 | create_send_and_recv_data(id, is_client_con, send_channel_default_size); 99 | 100 | let ctx = Context::new(recv_msg, recv_control, recv_data, id, cnx, is_client_con); 101 | let stream = Stream { 102 | recv_msg: recv_send, 103 | control_msg, 104 | send_data, 105 | id, 106 | peer_addr: cnx.peer_addr(), 107 | local_addr, 108 | stream_reset: false, 109 | }; 110 | 111 | (stream, ctx) 112 | } 113 | 114 | /// Returns the type of this `Stream`, either `Type::Unidirectional` or `Type::Bidirectional`. 115 | pub fn get_type(&self) -> Type { 116 | if is_unidirectional(self.id) { 117 | Type::Unidirectional 118 | } else { 119 | Type::Bidirectional 120 | } 121 | } 122 | 123 | /// Returns the address of the `Connection`'s peer. 124 | pub fn peer_addr(&self) -> SocketAddr { 125 | self.peer_addr 126 | } 127 | 128 | /// Returns the address of the `Connection`'s local `Context`, where it is listening on. 129 | pub fn local_addr(&self) -> SocketAddr { 130 | self.local_addr 131 | } 132 | 133 | /// Resets this stream. 134 | pub fn reset(&mut self) -> Result<(), Error> { 135 | self.control_msg 136 | .unbounded_send(Message::Reset) 137 | .map_err(|_| ErrorKind::Unknown.into()) 138 | } 139 | 140 | /// Returns if this stream received a reset. 141 | pub fn is_reset(&self) -> bool { 142 | self.stream_reset 143 | } 144 | 145 | /// Returns the `send_data` channel. 146 | fn get_send_data(&mut self) -> Result<&mut SenderWithError, Error> { 147 | self.send_data 148 | .as_mut() 149 | .ok_or_else(|| ErrorKind::SendOnUnidirectional.into()) 150 | } 151 | 152 | /// Set the size of the send channel. 153 | /// 154 | pub fn set_send_channel_size(&mut self, size: usize) { 155 | if let Some(old_sender) = self.send_data.take() { 156 | let (sender, receiver) = channel_with_error(size); 157 | self.send_data = Some(sender); 158 | let _ = self 159 | .control_msg 160 | .unbounded_send(Message::SwapSendData((receiver, old_sender))); 161 | } 162 | } 163 | } 164 | 165 | impl FStream for Stream { 166 | type Item = BytesMut; 167 | type Error = Error; 168 | 169 | fn poll(&mut self) -> Poll, Self::Error> { 170 | match try_ready!(self 171 | .recv_msg 172 | .poll() 173 | .map_err(|_| Error::from(ErrorKind::Unknown))) 174 | { 175 | Some(Message::Close) | None => Ok(Ready(None)), 176 | Some(Message::RecvData(d)) => Ok(Ready(Some(d))), 177 | Some(Message::Error(err)) => Err(err), 178 | Some(Message::Reset) => { 179 | self.stream_reset = true; 180 | Ok(Ready(None)) 181 | } 182 | Some(Message::SwapSendData(_)) => panic!("SwapSendData received!"), 183 | } 184 | } 185 | } 186 | 187 | impl Sink for Stream { 188 | type SinkItem = Bytes; 189 | type SinkError = Error; 190 | 191 | fn start_send(&mut self, item: Self::SinkItem) -> StartSend { 192 | self.get_send_data()?.start_send(item).map_err(|e| match e { 193 | SendError::Channel(e, _) => e, 194 | SendError::Normal(e) => ErrorKind::SendError(e.into_inner()).into(), 195 | }) 196 | } 197 | 198 | fn poll_complete(&mut self) -> Poll<(), Self::SinkError> { 199 | self.get_send_data()? 200 | .poll_complete() 201 | .map_err(|_| ErrorKind::Unknown.into()) 202 | } 203 | } 204 | 205 | pub(crate) struct Context { 206 | recv_msg: UnboundedSender, 207 | send_data: Option>>, 208 | control_msg: UnboundedReceiver, 209 | id: Id, 210 | cnx: ffi::Connection, 211 | /// Is the connection this Stream belongs to, a client connection? 212 | is_client_con: bool, 213 | /// Did this stream send any data? 214 | data_send: bool, 215 | 216 | stop_sending_or_fin_sent: bool, 217 | 218 | fin_received_or_recv_msg_dropped: bool, 219 | 220 | /// The active buffer that is currently fetched when this stream wants to send data. 221 | active_buffer: Option, 222 | } 223 | 224 | impl Context { 225 | fn new( 226 | recv_msg: UnboundedSender, 227 | mut control_msg: UnboundedReceiver, 228 | mut send_data: Option>, 229 | id: Id, 230 | cnx: ffi::Connection, 231 | is_client_con: bool, 232 | ) -> Context { 233 | let _ = control_msg.poll(); 234 | 235 | if let Some(s) = send_data.as_mut() { 236 | let _ = s.poll(); 237 | } 238 | 239 | let fin_received_or_recv_msg_dropped = 240 | is_unidirectional(id) && is_unidirectional_send_allowed(id, is_client_con); 241 | let stop_sending_or_fin_sent = 242 | is_unidirectional(id) && !is_unidirectional_send_allowed(id, is_client_con); 243 | 244 | Context { 245 | recv_msg, 246 | control_msg, 247 | send_data: send_data.map(|s| s.into()), 248 | id, 249 | cnx, 250 | is_client_con, 251 | data_send: false, 252 | stop_sending_or_fin_sent, 253 | fin_received_or_recv_msg_dropped, 254 | active_buffer: None, 255 | } 256 | } 257 | 258 | fn close_send_data(&mut self) { 259 | if let Some(mut s) = self.send_data.take() { 260 | s.close() 261 | } 262 | } 263 | 264 | fn reset(&mut self) { 265 | self.stop_sending_or_fin_sent = true; 266 | self.close_send_data(); 267 | 268 | unsafe { 269 | picoquic_reset_stream(self.cnx.as_ptr(), self.id, 0); 270 | } 271 | } 272 | 273 | fn recv_message(&mut self, msg: Message) { 274 | if self.recv_msg.unbounded_send(msg).is_err() { 275 | self.recv_message_dropped(); 276 | } 277 | } 278 | 279 | fn recv_message_dropped(&mut self) { 280 | if !self.fin_received_or_recv_msg_dropped { 281 | self.fin_received_or_recv_msg_dropped = true; 282 | 283 | if !is_unidirectional(self.id) 284 | || !is_unidirectional_send_allowed(self.id, self.is_client_con) 285 | { 286 | unsafe { 287 | picoquic_stop_sending(self.cnx.as_ptr(), self.id, 0); 288 | } 289 | } 290 | } 291 | } 292 | 293 | pub fn handle_callback( 294 | &mut self, 295 | ptr: *mut u8, 296 | length: usize, 297 | event: picoquic_call_back_event_t, 298 | ) { 299 | if event == picoquic::picoquic_call_back_event_t_picoquic_callback_prepare_to_send { 300 | self.handle_send_data(ptr, length); 301 | } else { 302 | let data = unsafe { slice::from_raw_parts(ptr, length) }; 303 | 304 | if !data.is_empty() && !self.fin_received_or_recv_msg_dropped { 305 | let data = BytesMut::from(data); 306 | self.recv_message(Message::RecvData(data)); 307 | } 308 | 309 | if event == picoquic::picoquic_call_back_event_t_picoquic_callback_stream_reset { 310 | self.fin_received_or_recv_msg_dropped = true; 311 | self.recv_message(Message::Reset); 312 | } else if event == picoquic::picoquic_call_back_event_t_picoquic_callback_stop_sending { 313 | self.stop_sending_or_fin_sent = true; 314 | self.close_send_data(); 315 | } else if event == picoquic::picoquic_call_back_event_t_picoquic_callback_stream_fin { 316 | self.fin_received_or_recv_msg_dropped = true; 317 | self.recv_message(Message::Close); 318 | } 319 | } 320 | } 321 | 322 | /// Handle a connection error. 323 | pub fn handle_connection_error(&mut self, err: impl ErrorFn) { 324 | self.recv_message(Message::Error(err())); 325 | if let Some(s) = self.send_data.as_mut() { 326 | s.propagate_error(err) 327 | } 328 | } 329 | 330 | /// Handle connection close. 331 | pub fn handle_connection_close(&mut self) { 332 | self.recv_message(Message::Close); 333 | } 334 | 335 | /// Collect buffers into the given `buffers` parameter that should be send. 336 | /// 337 | /// # Returns 338 | /// 339 | /// Returns the size of all collected buffers and if the `fin` bit should be set. 340 | fn collect_buffers_to_send( 341 | &mut self, 342 | max_length: usize, 343 | buffers: &mut SmallVec<[Bytes; 32]>, 344 | ) -> (usize, bool) { 345 | let mut size = 0; 346 | let mut fin = false; 347 | 348 | if let Some(buf) = self.active_buffer.take() { 349 | size += buf.len(); 350 | buffers.push(buf); 351 | } 352 | 353 | while size <= max_length { 354 | match self.send_data.as_mut() { 355 | Some(ref mut recv) => { 356 | match recv.poll().expect("Receiver never returns an error.") { 357 | Ready(Some(buf)) => { 358 | size += buf.len(); 359 | buffers.push(buf); 360 | } 361 | Ready(None) => { 362 | fin = true; 363 | break; 364 | } 365 | NotReady => break, 366 | } 367 | } 368 | None => { 369 | fin = true; 370 | break; 371 | } 372 | } 373 | } 374 | 375 | (size, fin) 376 | } 377 | 378 | /// Picoquic wants to send data and our `Stream` was marked as active. 379 | fn handle_send_data(&mut self, ctx: *mut u8, max_length: usize) { 380 | let mut buffers = SmallVec::new(); 381 | let (size, fin) = self.collect_buffers_to_send(max_length, &mut buffers); 382 | 383 | self.data_send = self.data_send || size > 0; 384 | let still_active = size > max_length && !fin; 385 | let length = cmp::min(max_length, size); 386 | let dest_slice = unsafe { 387 | let dest = picoquic_provide_stream_data_buffer( 388 | ctx as _, 389 | length, 390 | fin as i32, 391 | still_active as i32, 392 | ); 393 | 394 | if dest.is_null() { 395 | panic!("Stream data buffer should never be NULL."); 396 | } 397 | 398 | slice::from_raw_parts_mut(dest, length) 399 | }; 400 | 401 | self.stop_sending_or_fin_sent = fin; 402 | 403 | let mut written = 0; 404 | buffers.into_iter().for_each(|mut buf| { 405 | if written < length { 406 | let end = cmp::min(written + buf.len(), length); 407 | let buf_end = end - written; 408 | dest_slice[written..end].copy_from_slice(&buf[0..buf_end]); 409 | buf.advance(end - written); 410 | written = end; 411 | } 412 | 413 | if !buf.is_empty() && self.active_buffer.is_none() { 414 | self.active_buffer = Some(buf); 415 | } else if !buf.is_empty() { 416 | panic!("Active buffer should never be set twice!"); 417 | } 418 | }); 419 | } 420 | 421 | fn handle_send_data_dropped(&mut self) { 422 | self.send_data.take(); 423 | 424 | if !self.data_send && self.active_buffer.is_none() { 425 | self.reset(); 426 | } else if !self.stop_sending_or_fin_sent { 427 | unsafe { 428 | // We will need to set the fin bit 429 | picoquic_mark_active_stream(self.cnx.as_ptr(), self.id, 1, ptr::null_mut()); 430 | } 431 | } 432 | } 433 | 434 | fn poll_control_msg(&mut self) -> Poll<(), Error> { 435 | loop { 436 | match try_ready!(self 437 | .control_msg 438 | .poll() 439 | .map_err(|_| Error::from(ErrorKind::Unknown))) 440 | { 441 | Some(Message::Reset) => { 442 | self.reset(); 443 | } 444 | Some(Message::SwapSendData((new_receiver, _old_sender))) => { 445 | // `_old_sender` can be dropped after we set the receiver to swap to 446 | if let Some(s) = self.send_data.as_mut() { 447 | s.set_swap_to(new_receiver) 448 | } 449 | } 450 | None => { 451 | self.recv_message_dropped(); 452 | return Ok(Ready(())); 453 | } 454 | r => panic!("Stream context unknown `Message`: {:?}", r), 455 | } 456 | } 457 | } 458 | 459 | fn poll_send_data(&mut self) -> Result<(), Error> { 460 | if let (None, Some(ref mut recv)) = (&self.active_buffer, self.send_data.as_mut()) { 461 | match recv.poll()? { 462 | Ready(Some(buf)) => { 463 | self.active_buffer = Some(buf); 464 | unsafe { 465 | picoquic_mark_active_stream(self.cnx.as_ptr(), self.id, 1, ptr::null_mut()); 466 | } 467 | } 468 | Ready(None) => self.handle_send_data_dropped(), 469 | _ => {} 470 | } 471 | } 472 | 473 | Ok(()) 474 | } 475 | } 476 | 477 | fn is_unidirectional(id: Id) -> bool { 478 | id & 2 != 0 479 | } 480 | 481 | /// Returns if this Stream is the sending side of an unidirectional Stream. 482 | fn is_unidirectional_send_allowed(id: Id, is_client_con: bool) -> bool { 483 | if is_client_initiated(id) { 484 | is_client_con 485 | } else { 486 | !is_client_con 487 | } 488 | } 489 | 490 | /// Is the Stream initiated by the client? 491 | fn is_client_initiated(id: Id) -> bool { 492 | id & 1 == 0 493 | } 494 | 495 | impl Future for Context { 496 | type Item = (); 497 | type Error = Error; 498 | 499 | fn poll(&mut self) -> Poll { 500 | self.poll_control_msg()?; 501 | self.poll_send_data()?; 502 | 503 | if self.stop_sending_or_fin_sent && self.fin_received_or_recv_msg_dropped { 504 | Ok(Ready(())) 505 | } else { 506 | Ok(NotReady) 507 | } 508 | } 509 | } 510 | 511 | impl Drop for Context { 512 | fn drop(&mut self) { 513 | let _ = self.recv_msg.unbounded_send(Message::Close); 514 | self.close_send_data(); 515 | } 516 | } 517 | -------------------------------------------------------------------------------- /src/connection.rs: -------------------------------------------------------------------------------- 1 | use crate::channel_with_error::{unbounded, SendError, UnboundedReceiver, UnboundedSender}; 2 | use crate::error::*; 3 | use crate::ffi::{self, QuicCtx}; 4 | use crate::stream::{self, Stream}; 5 | 6 | use picoquic_sys::picoquic::{ 7 | self, picoquic_call_back_event_t, picoquic_cnx_t, picoquic_set_callback, 8 | }; 9 | 10 | use futures::{ 11 | sync::{mpsc, oneshot}, 12 | Async::{NotReady, Ready}, 13 | Future, Poll, Sink, Stream as FStream, 14 | }; 15 | 16 | use std::{ 17 | collections::{ 18 | hash_map::Entry::{Occupied, Vacant}, 19 | HashMap, 20 | }, 21 | mem, 22 | net::SocketAddr, 23 | os::raw::c_void, 24 | ptr, 25 | sync::{Arc, Mutex}, 26 | time::Duration, 27 | }; 28 | 29 | pub type Id = u64; 30 | 31 | #[derive(Debug)] 32 | enum Message { 33 | NewStream(Stream), 34 | Close, 35 | Error(Error), 36 | } 37 | 38 | /// A `Connection` can either be `Incoming` or `Outgoing`. 39 | #[derive(Debug, PartialEq, Copy, Clone)] 40 | pub enum Type { 41 | /// The `Connection` was created, because a remote peer created it. 42 | Incoming, 43 | /// The `Connection` was created, because the local peer created it. 44 | Outgoing, 45 | } 46 | 47 | struct ConnectionBuilder { 48 | msg_recv: mpsc::UnboundedReceiver, 49 | close_send: oneshot::Sender<()>, 50 | peer_addr: SocketAddr, 51 | local_addr: SocketAddr, 52 | new_stream_handle: NewStreamHandle, 53 | ctype: Type, 54 | } 55 | 56 | impl ConnectionBuilder { 57 | fn new( 58 | msg_recv: mpsc::UnboundedReceiver, 59 | close_send: oneshot::Sender<()>, 60 | peer_addr: SocketAddr, 61 | local_addr: SocketAddr, 62 | new_stream_handle: NewStreamHandle, 63 | ctype: Type, 64 | ) -> ConnectionBuilder { 65 | ConnectionBuilder { 66 | msg_recv, 67 | close_send, 68 | peer_addr, 69 | local_addr, 70 | new_stream_handle, 71 | ctype, 72 | } 73 | } 74 | 75 | fn build(self, id: Id) -> Connection { 76 | Connection { 77 | msg_recv: self.msg_recv, 78 | close_send: Some(self.close_send), 79 | peer_addr: self.peer_addr, 80 | local_addr: self.local_addr, 81 | new_stream_handle: self.new_stream_handle, 82 | ctype: self.ctype, 83 | id, 84 | } 85 | } 86 | } 87 | 88 | /// Represents a connection to a peer. 89 | pub struct Connection { 90 | msg_recv: mpsc::UnboundedReceiver, 91 | close_send: Option>, 92 | peer_addr: SocketAddr, 93 | local_addr: SocketAddr, 94 | new_stream_handle: NewStreamHandle, 95 | id: Id, 96 | ctype: Type, 97 | } 98 | 99 | impl Connection { 100 | /// Returns the address of the peer, this `Connection` is connected to. 101 | pub fn peer_addr(&self) -> SocketAddr { 102 | self.peer_addr 103 | } 104 | 105 | /// Returns the address of the local `Context`, where it is listening on. 106 | pub fn local_addr(&self) -> SocketAddr { 107 | self.local_addr 108 | } 109 | 110 | /// Returns the id of this `Connection`. 111 | /// The id is at the server and at the client the same. 112 | pub fn id(&self) -> Id { 113 | self.id 114 | } 115 | 116 | /// Returns the `Type` of this `Connection`. 117 | pub fn get_type(&self) -> Type { 118 | self.ctype 119 | } 120 | } 121 | 122 | impl FStream for Connection { 123 | type Item = Stream; 124 | type Error = Error; 125 | 126 | fn poll(&mut self) -> Poll, Self::Error> { 127 | match try_ready!(self 128 | .msg_recv 129 | .poll() 130 | .map_err(|_| Error::from(ErrorKind::Unknown))) 131 | { 132 | Some(Message::Close) | None => Ok(Ready(None)), 133 | Some(Message::NewStream(s)) => Ok(Ready(Some(s))), 134 | Some(Message::Error(e)) => Err(e), 135 | } 136 | } 137 | } 138 | 139 | impl Connection { 140 | /// Creates a new `Connection` from an incoming connection. 141 | pub(crate) fn from_incoming( 142 | cnx: *mut picoquic_cnx_t, 143 | stream_id: stream::Id, 144 | data: *mut u8, 145 | len: usize, 146 | event: picoquic_call_back_event_t, 147 | keep_alive_interval: Option, 148 | stream_send_channel_default_size: usize, 149 | ) -> (Connection, Arc>) { 150 | let cnx = ffi::Connection::from(cnx); 151 | 152 | let (builder, ctx, c_ctx) = Self::create_builder( 153 | cnx, 154 | cnx.peer_addr(), 155 | cnx.local_addr(), 156 | false, 157 | keep_alive_interval, 158 | stream_send_channel_default_size, 159 | ); 160 | 161 | let con = builder.build(cnx.local_id()); 162 | 163 | // Now we need to call the callback once manually to process the received data 164 | unsafe { 165 | connection_callback( 166 | cnx.as_ptr(), 167 | stream_id, 168 | data, 169 | len, 170 | event, 171 | c_ctx, 172 | ptr::null_mut(), 173 | ); 174 | } 175 | 176 | (con, ctx) 177 | } 178 | 179 | /// Creates a new `Connection` to the given `peer_addr` server. 180 | pub(crate) fn create( 181 | quic: &QuicCtx, 182 | peer_addr: SocketAddr, 183 | local_addr: SocketAddr, 184 | server_name: String, 185 | current_time: u64, 186 | keep_alive_interval: Option, 187 | created_sender: oneshot::Sender>, 188 | stream_send_channel_default_size: usize, 189 | ) -> Result>, Error> { 190 | let cnx = ffi::Connection::new(quic, peer_addr, current_time, server_name)?; 191 | 192 | let (builder, ctx, _) = Self::create_builder( 193 | cnx, 194 | peer_addr, 195 | local_addr, 196 | true, 197 | keep_alive_interval, 198 | stream_send_channel_default_size, 199 | ); 200 | 201 | // set the builder and the sender as waiting for ready state payload 202 | ctx.lock() 203 | .unwrap() 204 | .set_wait_for_ready_state(builder, created_sender); 205 | 206 | Ok(ctx) 207 | } 208 | 209 | fn create_builder( 210 | cnx: ffi::Connection, 211 | peer_addr: SocketAddr, 212 | local_addr: SocketAddr, 213 | is_client: bool, 214 | keep_alive_interval: Option, 215 | stream_send_channel_default_size: usize, 216 | ) -> (ConnectionBuilder, Arc>, *mut c_void) { 217 | let (sender, msg_recv) = mpsc::unbounded(); 218 | let (close_send, close_recv) = oneshot::channel(); 219 | 220 | let (ctx, c_ctx, new_stream_handle) = Context::new( 221 | cnx, 222 | sender, 223 | close_recv, 224 | is_client, 225 | local_addr, 226 | stream_send_channel_default_size, 227 | ); 228 | 229 | if let Some(interval) = keep_alive_interval { 230 | cnx.enable_keep_alive(interval); 231 | } 232 | 233 | let builder = ConnectionBuilder::new( 234 | msg_recv, 235 | close_send, 236 | peer_addr, 237 | local_addr, 238 | new_stream_handle, 239 | cnx.con_type(), 240 | ); 241 | 242 | (builder, ctx, c_ctx) 243 | } 244 | 245 | /// Creates a new bidirectional `Stream`. 246 | pub fn new_bidirectional_stream(&mut self) -> NewStreamFuture { 247 | self.new_stream_handle.new_bidirectional_stream() 248 | } 249 | 250 | /// Creates a new unidirectional `Stream`. 251 | pub fn new_unidirectional_stream(&mut self) -> NewStreamFuture { 252 | self.new_stream_handle.new_unidirectional_stream() 253 | } 254 | 255 | /// Returns a handle to create new `Stream`s for this connection. 256 | pub fn get_new_stream_handle(&self) -> NewStreamHandle { 257 | self.new_stream_handle.clone() 258 | } 259 | 260 | /// Immediately closes this connection. 261 | /// Any buffered data will be discarded. 262 | /// This function should only be used, if the application layer negotiated a close of the 263 | /// connection. 264 | pub fn close_immediately(mut self) { 265 | self.close_send.take().map(|s| s.send(())); 266 | } 267 | } 268 | 269 | pub(crate) struct Context { 270 | send_msg: mpsc::UnboundedSender, 271 | close_recv: oneshot::Receiver<()>, 272 | recv_create_stream: UnboundedReceiver<(stream::Type, oneshot::Sender>)>, 273 | streams: HashMap, 274 | cnx: ffi::Connection, 275 | closed: bool, 276 | /// Is the connection initiated by us? 277 | is_client: bool, 278 | next_stream_id: u64, 279 | /// If we create an outgoing connection, we postpone the `Connection` creation to the point 280 | /// where the connection state is ready. This is necessary, because some information that we 281 | /// require for the `Connection` object is not available up to this point. 282 | wait_for_ready_state: Option<( 283 | ConnectionBuilder, 284 | oneshot::Sender>, 285 | )>, 286 | local_addr: SocketAddr, 287 | stream_send_channel_default_size: usize, 288 | } 289 | 290 | impl Context { 291 | fn new( 292 | cnx: ffi::Connection, 293 | send_msg: mpsc::UnboundedSender, 294 | close_recv: oneshot::Receiver<()>, 295 | is_client: bool, 296 | local_addr: SocketAddr, 297 | stream_send_channel_default_size: usize, 298 | ) -> (Arc>, *mut c_void, NewStreamHandle) { 299 | let (send_create_stream, mut recv_create_stream) = unbounded(); 300 | 301 | let new_stream_handle = NewStreamHandle { 302 | send: send_create_stream, 303 | }; 304 | 305 | let _ = recv_create_stream.poll(); 306 | 307 | let ctx = Arc::new(Mutex::new(Context { 308 | send_msg, 309 | streams: Default::default(), 310 | cnx, 311 | closed: false, 312 | recv_create_stream, 313 | is_client, 314 | next_stream_id: 0, 315 | wait_for_ready_state: None, 316 | local_addr, 317 | close_recv, 318 | stream_send_channel_default_size, 319 | })); 320 | 321 | // Convert the `Context` to a `*mut c_void` and reset the callback to the 322 | // `recv_data_callback` 323 | let c_ctx = unsafe { 324 | let c_ctx = Arc::into_raw(ctx.clone()) as *mut c_void; 325 | picoquic_set_callback(cnx.as_ptr(), Some(connection_callback), c_ctx); 326 | c_ctx 327 | }; 328 | 329 | // The reference counter needs to be 2 at this point 330 | assert_eq!(2, Arc::strong_count(&ctx)); 331 | 332 | (ctx, c_ctx, new_stream_handle) 333 | } 334 | 335 | fn handle_stream_callback( 336 | &mut self, 337 | id: stream::Id, 338 | ptr: *mut u8, 339 | length: usize, 340 | event: picoquic_call_back_event_t, 341 | ) { 342 | let new_stream_handle = match self.streams.entry(id) { 343 | Occupied(mut entry) => { 344 | entry.get_mut().handle_callback(ptr, length, event); 345 | None 346 | } 347 | Vacant(entry) => { 348 | let (stream, mut ctx) = Stream::new( 349 | id, 350 | self.cnx, 351 | self.local_addr, 352 | self.is_client, 353 | self.stream_send_channel_default_size, 354 | ); 355 | 356 | ctx.handle_callback(ptr, length, event); 357 | entry.insert(ctx); 358 | Some(stream) 359 | } 360 | }; 361 | 362 | if let Some(stream) = new_stream_handle { 363 | let _ = self.send_msg.unbounded_send(Message::NewStream(stream)); 364 | } 365 | } 366 | 367 | fn handle_callback( 368 | &mut self, 369 | id: stream::Id, 370 | ptr: *mut u8, 371 | length: usize, 372 | event: picoquic_call_back_event_t, 373 | ) { 374 | if event == picoquic::picoquic_call_back_event_t_picoquic_callback_almost_ready { 375 | // maybe move to `callback_ready` 376 | if self.wait_for_ready_state.is_some() { 377 | self.process_wait_for_ready_state(); 378 | } 379 | } else if id != 0 { 380 | self.handle_stream_callback(id, ptr, length, event); 381 | } 382 | } 383 | 384 | /// Check for new streams to create and create these requested streams. 385 | fn check_create_stream_requests(&mut self) { 386 | loop { 387 | match self.recv_create_stream.poll() { 388 | Ok(Ready(None)) | Ok(NotReady) | Err(_) => break, 389 | Ok(Ready(Some((stype, sender)))) => { 390 | let id = ffi::Connection::generate_stream_id( 391 | self.next_stream_id, 392 | self.is_client, 393 | stype, 394 | ); 395 | self.next_stream_id += 1; 396 | 397 | let (stream, ctx) = Stream::new( 398 | id, 399 | self.cnx, 400 | self.local_addr, 401 | self.is_client, 402 | self.stream_send_channel_default_size, 403 | ); 404 | assert!(self.streams.insert(id, ctx).is_none()); 405 | 406 | let _ = sender.send(Ok(stream)); 407 | } 408 | } 409 | } 410 | } 411 | 412 | fn close(&mut self) { 413 | self.cnx.close(); 414 | self.closed = true; 415 | self.streams 416 | .values_mut() 417 | .for_each(|s| s.handle_connection_close()); 418 | let _ = self.send_msg.unbounded_send(Message::Close); 419 | } 420 | 421 | fn process_wait_for_ready_state(&mut self) { 422 | match self.wait_for_ready_state.take() { 423 | Some((builder, sender)) => { 424 | let id = self.cnx.local_id(); 425 | let con = builder.build(id); 426 | 427 | let _ = sender.send(Ok(con)); 428 | } 429 | None => panic!("connection can only switches once into `ready` state!"), 430 | }; 431 | } 432 | 433 | fn set_wait_for_ready_state( 434 | &mut self, 435 | builder: ConnectionBuilder, 436 | sender: oneshot::Sender>, 437 | ) { 438 | self.wait_for_ready_state = Some((builder, sender)); 439 | } 440 | 441 | /// Checks if the connection had an error and handles it. 442 | fn check_and_handle_error(&mut self) { 443 | if let Some(err) = self.cnx.error() { 444 | self.streams 445 | .values_mut() 446 | .for_each(|s| s.handle_connection_error(err.clone())); 447 | 448 | self.recv_create_stream.propagate_error(err.clone()); 449 | self.recv_create_stream.close(); 450 | while let Ok(Ready(Some((_, sender)))) = self.recv_create_stream.poll() { 451 | let _ = sender.send(Err(err())); 452 | } 453 | 454 | match self.wait_for_ready_state.take() { 455 | Some((_, send)) => { 456 | let _ = send.send(Err(err())); 457 | } 458 | None => { 459 | let _ = self.send_msg.unbounded_send(Message::Error(err())); 460 | } 461 | } 462 | } 463 | } 464 | } 465 | 466 | impl Future for Context { 467 | type Item = (); 468 | type Error = (); 469 | 470 | fn poll(&mut self) -> Poll { 471 | if self.closed { 472 | return Ok(Ready(())); 473 | } 474 | 475 | self.streams 476 | .retain(|_, s| s.poll().map(|r| r.is_not_ready()).unwrap_or(false)); 477 | 478 | self.check_create_stream_requests(); 479 | 480 | // Check if the connection should be closed 481 | if let Ok(Ready(_)) = self.close_recv.poll() { 482 | self.close(); 483 | } 484 | 485 | Ok(NotReady) 486 | } 487 | } 488 | 489 | impl Drop for Context { 490 | fn drop(&mut self) { 491 | unsafe { 492 | picoquic_set_callback(self.cnx.as_ptr(), None, ptr::null_mut()); 493 | } 494 | } 495 | } 496 | 497 | fn get_context(ctx: *mut c_void) -> Arc> { 498 | unsafe { Arc::from_raw(ctx as *mut Mutex) } 499 | } 500 | 501 | unsafe extern "C" fn connection_callback( 502 | _: *mut picoquic_cnx_t, 503 | stream_id: stream::Id, 504 | bytes: *mut u8, 505 | length: usize, 506 | event: picoquic_call_back_event_t, 507 | ctx: *mut c_void, 508 | _: *mut c_void, 509 | ) -> i32 { 510 | assert!(!ctx.is_null()); 511 | let ctx = get_context(ctx); 512 | 513 | if event == picoquic::picoquic_call_back_event_t_picoquic_callback_close 514 | || event == picoquic::picoquic_call_back_event_t_picoquic_callback_application_close 515 | { 516 | // when Arc goes out of scope, it will dereference the Context pointer automatically 517 | let mut ctx = ctx.lock().unwrap(); 518 | ctx.check_and_handle_error(); 519 | ctx.close(); 520 | } else { 521 | ctx.lock() 522 | .unwrap() 523 | .handle_callback(stream_id, bytes, length, event); 524 | 525 | // the context must not be dereferenced! 526 | mem::forget(ctx); 527 | } 528 | 529 | 0 530 | } 531 | 532 | /// A handle to create new `Stream`s for a connection. 533 | #[derive(Clone)] 534 | pub struct NewStreamHandle { 535 | send: UnboundedSender<(stream::Type, oneshot::Sender>)>, 536 | } 537 | 538 | impl NewStreamHandle { 539 | /// Creates a new bidirectional `Stream`. 540 | pub fn new_bidirectional_stream(&mut self) -> NewStreamFuture { 541 | self.new_stream_handle(stream::Type::Bidirectional) 542 | } 543 | 544 | /// Creates a new unidirectional `Stream`. 545 | pub fn new_unidirectional_stream(&mut self) -> NewStreamFuture { 546 | self.new_stream_handle(stream::Type::Unidirectional) 547 | } 548 | 549 | fn new_stream_handle(&mut self, stype: stream::Type) -> NewStreamFuture { 550 | let (send, recv) = oneshot::channel(); 551 | 552 | let _ = self.send.start_send((stype, send)).map_err(|e| match e { 553 | SendError::Channel(e, send) => send.into_inner().1.send(Err(e)), 554 | SendError::Normal(send) => send.into_inner().1.send(Err(ErrorKind::Unknown.into())), 555 | }); 556 | 557 | NewStreamFuture { recv } 558 | } 559 | } 560 | 561 | /// A future that resolves to a `Stream`. 562 | /// This future is created by the `NewStreamHandle`. 563 | pub struct NewStreamFuture { 564 | recv: oneshot::Receiver>, 565 | } 566 | 567 | impl Future for NewStreamFuture { 568 | type Item = Stream; 569 | type Error = Error; 570 | 571 | fn poll(&mut self) -> Poll { 572 | self.recv 573 | .poll() 574 | .map_err(|_| ErrorKind::Unknown.into()) 575 | .and_then(|r| match r { 576 | Ready(v) => v.map(Ready), 577 | NotReady => Ok(NotReady), 578 | }) 579 | } 580 | } 581 | -------------------------------------------------------------------------------- /tests/integration.rs: -------------------------------------------------------------------------------- 1 | use futures; 2 | 3 | use timebomb; 4 | use tokio; 5 | 6 | use picoquic::{ 7 | default_verify_certificate, Config, Connection, ConnectionId, ConnectionType, Context, Error, 8 | ErrorKind, FileFormat, NewStreamFuture, NewStreamHandle, SType, Stream, VerifyCertificate, 9 | }; 10 | 11 | use std::{ 12 | cmp, fmt, 13 | net::SocketAddr, 14 | sync::{ 15 | atomic::{AtomicUsize, Ordering}, 16 | Arc, 17 | }, 18 | time::{Duration, Instant}, 19 | }; 20 | 21 | use futures::{future, stream, sync::mpsc::unbounded, Future, Sink, Stream as FStream}; 22 | 23 | use bytes::{Bytes, BytesMut}; 24 | 25 | use openssl::{ 26 | error::ErrorStack, 27 | stack::StackRef, 28 | x509::{store::X509StoreBuilder, X509Ref, X509}, 29 | }; 30 | 31 | use tokio::{ 32 | runtime::{Runtime, TaskExecutor}, 33 | timer::{Delay, Interval}, 34 | }; 35 | 36 | use rand::{self, Rng}; 37 | 38 | const TEST_SERVER_NAME: &str = "picoquic.test"; 39 | 40 | fn get_test_certs_path() -> String { 41 | let manifest_dir = env!("CARGO_MANIFEST_DIR"); 42 | format!("{}/tests/certs/", manifest_dir) 43 | } 44 | 45 | fn get_test_config() -> Config { 46 | let mut config = Config::new(); 47 | config.set_certificate_chain_filename(format!("{}device.test.crt", get_test_certs_path())); 48 | config.set_private_key_filename(format!("{}device.key", get_test_certs_path())); 49 | config.set_root_certificate_filename(format!("{}ca.crt", get_test_certs_path())); 50 | config 51 | } 52 | 53 | fn create_context_and_evt_loop_with_default_config() -> (Context, Runtime) { 54 | create_context_and_evt_loop(get_test_config()) 55 | } 56 | 57 | fn create_context_and_evt_loop(config: Config) -> (Context, Runtime) { 58 | let evt_loop = Runtime::new().expect("creates event loop"); 59 | 60 | let context = Context::new(&([0, 0, 0, 0], 0).into(), evt_loop.executor(), config) 61 | .expect("creates quic context"); 62 | 63 | (context, evt_loop) 64 | } 65 | 66 | fn start_server_thread_with_default_config( 67 | executor: TaskExecutor, 68 | create_future: F, 69 | ) -> SocketAddr 70 | where 71 | F: 'static + Send + FnOnce(Context) -> R, 72 | R: Future + Send + 'static, 73 | ::Item: Send + 'static, 74 | ::Error: fmt::Debug + Send + 'static, 75 | { 76 | start_server_thread(executor, get_test_config, create_future) 77 | } 78 | 79 | fn start_server_thread( 80 | executor: TaskExecutor, 81 | create_config: C, 82 | create_future: F, 83 | ) -> SocketAddr 84 | where 85 | F: 'static + Send + FnOnce(Context) -> R, 86 | R: Future + Send + 'static, 87 | ::Error: fmt::Debug + Send + 'static, 88 | ::Item: Send + 'static, 89 | C: 'static + Send + FnOnce() -> Config, 90 | { 91 | let context = Context::new(&([0, 0, 0, 0], 0).into(), executor.clone(), create_config()) 92 | .expect("creates quic context"); 93 | 94 | let local_addr = context.local_addr(); 95 | 96 | executor.spawn(create_future(context).map_err(|e| panic!(e)).map(|_| ())); 97 | 98 | local_addr 99 | } 100 | 101 | #[test] 102 | fn server_start() { 103 | let runtime = Runtime::new().unwrap(); 104 | start_server_thread_with_default_config(runtime.executor(), |c| c.for_each(|_| Ok(()))); 105 | } 106 | 107 | fn client_connects_creates_stream_and_sends_data( 108 | client_config: Config, 109 | create_server_config: C, 110 | create_stream: F, 111 | check_type: T, 112 | ) where 113 | F: Fn(Connection) -> (NewStreamFuture, Connection), 114 | T: Fn(&Stream), 115 | C: 'static + Send + FnOnce() -> Config, 116 | { 117 | let send_data = "hello server"; 118 | let (send, recv) = unbounded(); 119 | let (mut context, mut evt_loop) = create_context_and_evt_loop(client_config); 120 | 121 | let addr = start_server_thread(evt_loop.executor(), create_server_config, move |c| { 122 | c.for_each(move |c| { 123 | assert_eq!(c.get_type(), ConnectionType::Incoming); 124 | let send = send.clone(); 125 | c.for_each(move |s| { 126 | let send = send.clone(); 127 | s.for_each(move |m| { 128 | let _ = send 129 | .clone() 130 | .unbounded_send(String::from_utf8(m.to_vec()).unwrap()); 131 | Ok(()) 132 | }) 133 | }) 134 | }) 135 | }); 136 | 137 | let con = evt_loop 138 | .block_on(context.new_connection(([127, 0, 0, 1], addr.port()).into(), TEST_SERVER_NAME)) 139 | .expect("creates connection"); 140 | assert_eq!(con.get_type(), ConnectionType::Outgoing); 141 | 142 | let (new_stream, _con) = create_stream(con); 143 | let stream = evt_loop.block_on(new_stream).expect("creates stream"); 144 | check_type(&stream); 145 | 146 | assert_eq!( 147 | stream.local_addr(), 148 | ([0, 0, 0, 0], context.local_addr().port()).into() 149 | ); 150 | assert_eq!(stream.peer_addr(), ([127, 0, 0, 1], addr.port()).into()); 151 | assert_ne!(stream.peer_addr(), stream.local_addr()); 152 | 153 | let _stream = evt_loop 154 | .block_on(stream.send(Bytes::from(send_data))) 155 | .unwrap(); 156 | 157 | assert_eq!( 158 | send_data, 159 | evt_loop.block_on(recv.into_future()).unwrap().0.unwrap() 160 | ); 161 | } 162 | 163 | fn client_connects_creates_bidirectional_stream_and_sends_data_impl( 164 | client_config: Config, 165 | create_server_config: C, 166 | ) where 167 | C: 'static + Send + FnOnce() -> Config, 168 | { 169 | client_connects_creates_stream_and_sends_data( 170 | client_config, 171 | create_server_config, 172 | |mut c| { 173 | let stream = c.new_bidirectional_stream(); 174 | (stream, c) 175 | }, 176 | |s| { 177 | assert!(match s.get_type() { 178 | SType::Bidirectional => true, 179 | _ => false, 180 | }) 181 | }, 182 | ) 183 | } 184 | 185 | #[test] 186 | fn client_connects_creates_bidirectional_stream_and_sends_data() { 187 | client_connects_creates_bidirectional_stream_and_sends_data_impl(get_test_config(), || { 188 | get_test_config() 189 | }); 190 | } 191 | 192 | #[test] 193 | fn client_connects_creates_unidirectional_stream_and_sends_data() { 194 | client_connects_creates_stream_and_sends_data( 195 | get_test_config(), 196 | get_test_config, 197 | |mut c| { 198 | let stream = c.new_unidirectional_stream(); 199 | (stream, c) 200 | }, 201 | |s| { 202 | assert!(match s.get_type() { 203 | SType::Unidirectional => true, 204 | _ => false, 205 | }) 206 | }, 207 | ) 208 | } 209 | 210 | #[test] 211 | fn empty_stream_reset_and_no_more_send_on_drop() { 212 | timebomb::timeout_ms(empty_stream_reset_and_no_more_send_on_drop_inner, 10000); 213 | } 214 | 215 | fn empty_stream_reset_and_no_more_send_on_drop_inner() { 216 | let send_data = "hello server"; 217 | 218 | let (mut context, mut evt_loop) = create_context_and_evt_loop_with_default_config(); 219 | 220 | let addr = start_server_thread_with_default_config(evt_loop.executor(), move |c| { 221 | c.for_each(move |c| { 222 | tokio::spawn( 223 | c.for_each(move |s| s.into_future().map(|_| ()).map_err(|e| e.0)) 224 | .map_err(|_| ()), 225 | ); 226 | 227 | Ok(()) 228 | }) 229 | }); 230 | 231 | let mut con = evt_loop 232 | .block_on(context.new_connection(([127, 0, 0, 1], addr.port()).into(), TEST_SERVER_NAME)) 233 | .expect("creates connection"); 234 | 235 | let stream = evt_loop 236 | .block_on(con.new_bidirectional_stream()) 237 | .expect("creates stream"); 238 | 239 | let stream = evt_loop 240 | .block_on(stream.send(Bytes::from(send_data))) 241 | .unwrap(); 242 | 243 | let (result, stream) = evt_loop 244 | .block_on(stream.into_future().map_err(|(e, _)| e)) 245 | .unwrap(); 246 | 247 | assert_eq!(result, None); 248 | assert!(stream.is_reset()); 249 | // Send data in a loop, as `stop_sending` is processed after `reset` and to prevent race 250 | // conditions, we need to try sending multiple times. 251 | assert!(evt_loop 252 | .block_on(futures::lazy(move || stream.send_all( 253 | Interval::new(Instant::now(), Duration::from_millis(100)) 254 | .map_err(|_| Error::from(ErrorKind::Unknown)) 255 | .map(|_| Bytes::from("error")) 256 | ))) 257 | .is_err()); 258 | } 259 | 260 | #[test] 261 | fn none_empty_stream_set_fin_bit_on_drop() { 262 | timebomb::timeout_ms(none_empty_stream_set_fin_bit_on_drop_inner, 10000); 263 | } 264 | 265 | fn none_empty_stream_set_fin_bit_on_drop_inner() { 266 | let send_data = "hello server"; 267 | 268 | let (mut context, mut evt_loop) = create_context_and_evt_loop_with_default_config(); 269 | 270 | let addr = start_server_thread_with_default_config(evt_loop.executor(), move |c| { 271 | c.for_each(move |c| { 272 | tokio::spawn( 273 | c.for_each(move |s| s.send(Bytes::from(send_data)).map(|_| ())) 274 | .map_err(|_| ()), 275 | ); 276 | 277 | Ok(()) 278 | }) 279 | }); 280 | 281 | let mut con = evt_loop 282 | .block_on(context.new_connection(([127, 0, 0, 1], addr.port()).into(), TEST_SERVER_NAME)) 283 | .expect("creates connection"); 284 | 285 | let stream = evt_loop 286 | .block_on( 287 | con.new_bidirectional_stream() 288 | .and_then(move |s| s.send(Bytes::from(send_data))), 289 | ) 290 | .expect("creates stream"); 291 | 292 | let (result, stream) = evt_loop 293 | .block_on(stream.into_future().map_err(|(e, _)| e)) 294 | .unwrap(); 295 | 296 | assert_eq!( 297 | send_data, 298 | &String::from_utf8(result.unwrap().to_vec()).unwrap() 299 | ); 300 | 301 | let (result, stream) = evt_loop 302 | .block_on(stream.into_future().map_err(|(e, _)| e)) 303 | .unwrap(); 304 | assert_eq!(result, None); 305 | 306 | assert!(!stream.is_reset()); 307 | } 308 | 309 | fn start_server_that_sends_received_data_back( 310 | executor: TaskExecutor, 311 | create_config: C, 312 | ) -> SocketAddr 313 | where 314 | C: 'static + Send + FnOnce() -> Config, 315 | { 316 | start_server_thread(executor, create_config, move |c| { 317 | c.for_each(move |c| { 318 | tokio::spawn( 319 | c.for_each(move |s| { 320 | // Peer addr and local addr can not be the same 321 | assert_ne!(s.peer_addr(), s.local_addr()); 322 | // The local address should be unspecified, as we do not set a specific address in 323 | // the tests. 324 | assert!(s.local_addr().ip().is_unspecified()); 325 | 326 | let (send, recv) = s.split(); 327 | 328 | tokio::spawn( 329 | send.send_all(recv.map(BytesMut::freeze)) 330 | .map(|_| ()) 331 | .map_err(|_| ()), 332 | ); 333 | Ok(()) 334 | }) 335 | .map_err(|_| ()), 336 | ); 337 | 338 | Ok(()) 339 | }) 340 | }) 341 | } 342 | 343 | #[test] 344 | fn open_multiple_streams_sends_data_and_recvs() { 345 | let send_data = "hello server"; 346 | let stream_count = 4; 347 | let mut data = Vec::new(); 348 | 349 | for i in 0..stream_count { 350 | data.push(vec![Bytes::from(format!("{}{}", send_data, i))]); 351 | } 352 | 353 | open_multiple_streams_sends_data_and_recvs_impl(data); 354 | } 355 | 356 | fn open_multiple_streams_sends_data_and_recvs_impl(data: Vec>) { 357 | let (mut context, mut evt_loop) = create_context_and_evt_loop_with_default_config(); 358 | let addr = start_server_that_sends_received_data_back(evt_loop.executor(), get_test_config); 359 | 360 | let mut con = evt_loop 361 | .block_on(context.new_connection(([127, 0, 0, 1], addr.port()).into(), TEST_SERVER_NAME)) 362 | .expect("creates connection"); 363 | 364 | let mut streams = Vec::new(); 365 | 366 | for send in &data { 367 | let stream = evt_loop 368 | .block_on(con.new_bidirectional_stream()) 369 | .expect("creates stream"); 370 | streams.push( 371 | stream 372 | .send_all(stream::iter_ok::<_, Error>(send.clone().into_iter())) 373 | .map(|v| v.0), 374 | ); 375 | } 376 | 377 | let streams = evt_loop.block_on(future::join_all(streams)).unwrap(); 378 | 379 | for (stream, data) in streams.into_iter().zip(data.into_iter()) { 380 | let all_data = data.into_iter().fold(Vec::new(), |mut v, d| { 381 | v.extend(&d); 382 | v 383 | }); 384 | let all_len = all_data.len(); 385 | let res = evt_loop 386 | .block_on( 387 | stream 388 | .map_err(|_| Vec::new()) 389 | .fold(Vec::new(), move |mut v, b| { 390 | v.extend(&b); 391 | 392 | if v.len() < all_len { 393 | future::ok(v) 394 | } else { 395 | future::err(v) 396 | } 397 | }), 398 | ) 399 | .err() 400 | .unwrap(); 401 | 402 | assert_eq!(&all_data, &res); 403 | } 404 | } 405 | 406 | #[test] 407 | fn open_multiple_streams_sends_1mb_data_and_recvs() { 408 | let stream_count = 4; 409 | let mut data = Vec::new(); 410 | 411 | for _ in 0..stream_count { 412 | let mut send_data = vec![0; 1024 * 1024]; 413 | rand::thread_rng().fill(&mut send_data[..]); 414 | data.push(vec![Bytes::from(send_data)]); 415 | } 416 | 417 | open_multiple_streams_sends_data_and_recvs_impl(data); 418 | } 419 | 420 | fn create_chunked_data(size: usize) -> Vec { 421 | let mut send_data = vec![0; size]; 422 | rand::thread_rng().fill(&mut send_data[..]); 423 | let chunks = rand::thread_rng().gen_range(100, 1000); 424 | let chunk_size = (send_data.len() + chunks - 1) / chunks; 425 | (0..chunks) 426 | .fold((Vec::new(), 0), |(mut v, i), _| { 427 | v.push(Bytes::from( 428 | &send_data[i..cmp::min(i + chunk_size, send_data.len())], 429 | )); 430 | (v, i + chunk_size) 431 | }) 432 | .0 433 | } 434 | 435 | #[test] 436 | fn open_multiple_streams_sends_1mb_data_in_chunks_and_recvs() { 437 | let stream_count = 4; 438 | let mut data = Vec::new(); 439 | 440 | for _ in 0..stream_count { 441 | data.push(create_chunked_data(1024 * 1024)); 442 | } 443 | 444 | open_multiple_streams_sends_data_and_recvs_impl(data); 445 | } 446 | 447 | #[test] 448 | fn open_stream_send_data_decrease_send_channel_size_send_data_and_recv_result() { 449 | let send_data = create_chunked_data(1024 * 1024); 450 | 451 | let (mut context, mut evt_loop) = create_context_and_evt_loop_with_default_config(); 452 | let addr = start_server_that_sends_received_data_back(evt_loop.executor(), get_test_config); 453 | 454 | let mut con = evt_loop 455 | .block_on(context.new_connection(([127, 0, 0, 1], addr.port()).into(), TEST_SERVER_NAME)) 456 | .expect("creates connection"); 457 | 458 | let send_data_inner = send_data.clone(); 459 | let mut stream = evt_loop 460 | .block_on(con.new_bidirectional_stream().and_then(move |stream| { 461 | stream 462 | .send_all(stream::iter_ok::<_, Error>(send_data_inner.into_iter())) 463 | .map(|v| v.0) 464 | })) 465 | .expect("creates stream and sends data"); 466 | 467 | stream.set_send_channel_size(1); 468 | 469 | let stream = evt_loop 470 | .block_on( 471 | stream 472 | .send_all(stream::iter_ok::<_, Error>(send_data.clone().into_iter())) 473 | .map(|v| v.0), 474 | ) 475 | .expect("sends data with smaller send channel size"); 476 | 477 | let mut all_data = send_data.into_iter().fold(Vec::new(), |mut v, d| { 478 | v.extend(&d); 479 | v 480 | }); 481 | // we send the data twice 482 | all_data.extend(all_data.clone().into_iter()); 483 | 484 | let all_len = all_data.len(); 485 | let res = evt_loop 486 | .block_on( 487 | stream 488 | .map_err(|_| Vec::new()) 489 | .fold(Vec::new(), move |mut v, b| { 490 | v.extend(&b); 491 | 492 | if v.len() < all_len { 493 | future::ok(v) 494 | } else { 495 | future::err(v) 496 | } 497 | }), 498 | ) 499 | .err() 500 | .unwrap(); 501 | 502 | assert_eq!(&all_data, &res); 503 | } 504 | 505 | fn open_stream_to_server_and_server_creates_new_stream_to_answer(create_stream: F) 506 | where 507 | F: 'static + Sync + Send + Fn(NewStreamHandle) -> NewStreamFuture, 508 | { 509 | let create_stream = Arc::new(Box::new(create_stream)); 510 | let send_data = "hello server"; 511 | 512 | let (mut context, mut evt_loop) = create_context_and_evt_loop_with_default_config(); 513 | 514 | let create_stream2 = create_stream.clone(); 515 | let addr = start_server_thread_with_default_config(evt_loop.executor(), move |c| { 516 | let create_stream = create_stream2; 517 | c.for_each(move |c| { 518 | let create_stream = create_stream.clone(); 519 | let new_stream = c.get_new_stream_handle(); 520 | 521 | c.for_each(move |incoming_stream| { 522 | let create_stream = create_stream.clone(); 523 | let new_stream = new_stream.clone(); 524 | 525 | create_stream(new_stream.clone()) 526 | .and_then(move |s| s.send_all(incoming_stream.map(BytesMut::freeze))) 527 | .map(|_| ()) 528 | }) 529 | }) 530 | }); 531 | 532 | let con = evt_loop 533 | .block_on(context.new_connection(([127, 0, 0, 1], addr.port()).into(), TEST_SERVER_NAME)) 534 | .expect("creates connection"); 535 | 536 | let stream = evt_loop 537 | .block_on(create_stream(con.get_new_stream_handle())) 538 | .expect("creates stream"); 539 | let _stream = evt_loop 540 | .block_on(stream.send(Bytes::from(send_data))) 541 | .unwrap(); 542 | 543 | let (new_stream, _con) = evt_loop 544 | .block_on( 545 | con.into_future() 546 | .map(|(m, c)| (m.unwrap(), c)) 547 | .map_err(|(e, _)| e), 548 | ) 549 | .unwrap(); 550 | 551 | assert_eq!( 552 | send_data, 553 | String::from_utf8( 554 | evt_loop 555 | .block_on(new_stream.into_future().map(|(m, _)| m).map_err(|(e, _)| e)) 556 | .unwrap() 557 | .unwrap() 558 | .to_vec() 559 | ) 560 | .unwrap() 561 | ); 562 | } 563 | 564 | #[test] 565 | fn open_uni_stream_to_server_and_server_creates_new_uni_stream_to_answer() { 566 | open_stream_to_server_and_server_creates_new_stream_to_answer(|mut h| { 567 | h.new_unidirectional_stream() 568 | }); 569 | } 570 | 571 | #[test] 572 | fn open_bi_stream_to_server_and_server_creates_new_bi_stream_to_answer() { 573 | open_stream_to_server_and_server_creates_new_stream_to_answer(|mut h| { 574 | h.new_bidirectional_stream() 575 | }); 576 | } 577 | 578 | #[derive(Clone)] 579 | struct VerifyCertificateImpl { 580 | counter: Arc, 581 | } 582 | 583 | impl VerifyCertificateImpl { 584 | fn new() -> VerifyCertificateImpl { 585 | VerifyCertificateImpl { 586 | counter: Arc::new(AtomicUsize::new(0)), 587 | } 588 | } 589 | 590 | fn increment(&self) { 591 | self.counter.fetch_add(1, Ordering::SeqCst); 592 | } 593 | 594 | fn get(&self) -> usize { 595 | self.counter.load(Ordering::SeqCst) 596 | } 597 | } 598 | 599 | impl VerifyCertificate for VerifyCertificateImpl { 600 | fn verify( 601 | &mut self, 602 | _: ConnectionId, 603 | _: ConnectionType, 604 | cert: &X509Ref, 605 | chain: &StackRef, 606 | ) -> Result { 607 | let ca_cert = include_bytes!("certs/ca.crt"); 608 | let ca_cert = X509::from_pem(ca_cert)?; 609 | 610 | let mut store_bldr = X509StoreBuilder::new().unwrap(); 611 | store_bldr.add_cert(ca_cert).unwrap(); 612 | let store = store_bldr.build(); 613 | 614 | let res = default_verify_certificate(cert, chain, &store); 615 | 616 | self.increment(); 617 | 618 | res 619 | } 620 | } 621 | 622 | fn verify_certificate_callback_is_called_and_certificate_is_verified( 623 | client_cert: String, 624 | client_key: String, 625 | ) -> Result<(), Error> { 626 | let send_data = "hello server"; 627 | let call_counter = VerifyCertificateImpl::new(); 628 | 629 | let mut client_config = get_test_config(); 630 | client_config.set_verify_certificate_handler(call_counter.clone()); 631 | client_config.set_certificate_chain_filename(client_cert); 632 | client_config.set_private_key_filename(client_key); 633 | 634 | let (mut context, mut evt_loop) = create_context_and_evt_loop(client_config); 635 | 636 | let server_call_counter = call_counter.clone(); 637 | let addr = start_server_that_sends_received_data_back(evt_loop.executor(), move || { 638 | let mut server_config = get_test_config(); 639 | server_config.set_verify_certificate_handler(server_call_counter); 640 | server_config.enable_client_authentication(); 641 | 642 | server_config 643 | }); 644 | 645 | let mut con = evt_loop 646 | .block_on(context.new_connection(([127, 0, 0, 1], addr.port()).into(), TEST_SERVER_NAME))?; 647 | 648 | let stream = evt_loop.block_on(con.new_bidirectional_stream())?; 649 | let stream = evt_loop.block_on(stream.send(Bytes::from(send_data)))?; 650 | 651 | assert_eq!( 652 | send_data, 653 | &String::from_utf8( 654 | evt_loop 655 | .block_on(stream.into_future().map(|(m, _)| m).map_err(|(e, _)| e))? 656 | .unwrap() 657 | .to_vec() 658 | ) 659 | .unwrap() 660 | ); 661 | 662 | assert_eq!(call_counter.get(), 2); 663 | Ok(()) 664 | } 665 | 666 | #[test] 667 | fn verify_certificate_callback_is_called_and_certificate_verification_succeeds() { 668 | assert!( 669 | verify_certificate_callback_is_called_and_certificate_is_verified( 670 | format!("{}device.test.crt", get_test_certs_path()), 671 | format!("{}device.key", get_test_certs_path()), 672 | ) 673 | .is_ok() 674 | ); 675 | } 676 | 677 | #[test] 678 | fn verify_certificate_callback_is_called_and_certificate_verification_fails() { 679 | assert_eq!( 680 | verify_certificate_callback_is_called_and_certificate_is_verified( 681 | format!("{}device.invalid.crt", get_test_certs_path()), 682 | format!("{}device.key", get_test_certs_path()), 683 | ) 684 | .err() 685 | .unwrap() 686 | .kind(), 687 | &ErrorKind::TLSHandshakeError 688 | ); 689 | } 690 | 691 | #[test] 692 | fn set_certificate_and_key_from_memory() { 693 | client_connects_creates_bidirectional_stream_and_sends_data_impl(get_test_config(), || { 694 | let cert = include_bytes!("certs/device.test.crt"); 695 | let key = include_bytes!("certs/device.key"); 696 | 697 | let mut config = get_test_config(); 698 | config.certificate_chain_filename = None; 699 | config.private_key_filename = None; 700 | config.set_certificate_chain(vec![cert.to_vec()], FileFormat::PEM); 701 | config.set_private_key(key.to_vec(), FileFormat::PEM); 702 | config 703 | }); 704 | } 705 | 706 | #[test] 707 | fn stream_stops_on_context_drop() { 708 | timebomb::timeout_ms(stream_stops_on_context_drop_inner, 10000); 709 | } 710 | 711 | fn stream_stops_on_context_drop_inner() { 712 | let send_data = "hello server"; 713 | 714 | let (mut context, mut evt_loop) = create_context_and_evt_loop_with_default_config(); 715 | 716 | let addr = start_server_that_sends_received_data_back(evt_loop.executor(), get_test_config); 717 | 718 | let mut con = evt_loop 719 | .block_on(context.new_connection(([127, 0, 0, 1], addr.port()).into(), TEST_SERVER_NAME)) 720 | .expect("creates connection"); 721 | 722 | let stream = evt_loop 723 | .block_on( 724 | con.new_bidirectional_stream() 725 | .and_then(move |s| s.send(Bytes::from(send_data))), 726 | ) 727 | .expect("creates stream"); 728 | 729 | let _ = evt_loop 730 | .block_on( 731 | stream 732 | .send_all( 733 | Interval::new(Instant::now(), Duration::from_millis(10)) 734 | .map_err(|_| Error::from(ErrorKind::Unknown)) 735 | .map(move |_| Bytes::from(send_data)), 736 | ) 737 | .map(|_| ()) 738 | .select( 739 | Delay::new(Instant::now() + Duration::from_millis(100)) 740 | .map_err(|_| ErrorKind::Unknown.into()) 741 | .map(move |_| { 742 | let _ = context; 743 | }), 744 | ), 745 | ) 746 | .map_err(|e| e.0) 747 | .unwrap(); 748 | 749 | assert!(evt_loop 750 | .block_on(con.into_future().map_err(|(e, _)| e).map(|v| v.0)) 751 | .unwrap() 752 | .is_none()); 753 | } 754 | --------------------------------------------------------------------------------