1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
// Copyright (C) 2020 Matthew Waters <matthew@centricular.com>
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//
// SPDX-License-Identifier: MIT OR Apache-2.0
//! # librice
//!
//! An async implementation based on [rice-proto] using the [rice-c] bindings.
//!
//! ## Relevant standards
//!
//! - [x] [RFC5245](https://tools.ietf.org/html/rfc5245):
//! Interactive Connectivity Establishment (ICE): A Protocol for Network Address
//! Translator (NAT) Traversal for Offer/Answer Protocols
//! - [x] [RFC5389](https://tools.ietf.org/html/rfc5389):
//! Session Traversal Utilities for NAT (STUN)
//! - [x] [RFC5766](https://tools.ietf.org/html/rfc5766):
//! Traversal Using Relays around NAT (TURN): Relay Extensions to Session
//! Traversal Utilities for NAT (STUN)
//! - [x] [RFC5769](https://tools.ietf.org/html/rfc5769):
//! Test Vectors for Session Traversal Utilities for NAT (STUN)
//! - [x] [RFC6062](https://tools.ietf.org/html/rfc6062):
//! Traversal Using Relays around NAT (TURN) Extensions for TCP Allocations
//! - [x] [RFC6156](https://tools.ietf.org/html/rfc6156):
//! Traversal Using Relays around NAT (TURN) Extension for IPv6
//! - [x] [RFC6544](https://tools.ietf.org/html/rfc6544):
//! TCP Candidates with Interactive Connectivity Establishment (ICE)
//! - [ ] [RFC7675](https://tools.ietf.org/html/rfc7675):
//! Session Traversal Utilities for NAT (STUN) Usage for Consent Freshness
//! - [x] [RFC8445]: Interactive Connectivity Establishment (ICE): A Protocol
//! for Network Address Translator (NAT) Traversal
//! - [x] [RFC8489](https://tools.ietf.org/html/rfc8489):
//! Session Traversal Utilities for NAT (STUN)
//! - [x] [RFC8656](https://tools.ietf.org/html/rfc8656):
//! Traversal Using Relays around NAT (TURN): Relay Extensions to Session
//! Traversal Utilities for NAT (STUN)
//! - [x] [RFC8838](https://tools.ietf.org/html/rfc8838):
//! Trickle ICE: Incremental Provisioning of Candidates for the Interactive
//! Connectivity Establishment (ICE) Protocol
//!
//! ## Building
//!
//! `librice` has the same build requirements as [rice-c] and the crate level documentation for
//! [rice-c] provides guidelines on how to build [rice-c] and projects that depend on [rice-c].
//!
//! [RFC8445]: <https://tools.ietf.org/html/rfc8445>
//! [rice-proto]: <https://docs.rs/rice-proto>
//! [rice-c]: <https://docs.rs/rice-c>
//!
//! ## Example
//!
//! ```
//! # #[cfg(feature = "runtime-tokio")]
//! # let runtime = tokio::runtime::Builder::new_current_thread()
//! # .enable_all()
//! # .build()
//! # .unwrap();
//! # #[cfg(feature = "runtime-tokio")]
//! # let _runtime = runtime.enter();
//! # let task = async move {
//! use core::net::SocketAddr;
//! use futures::stream::StreamExt;
//! use librice::agent::{Agent, AgentMessage};
//! use librice::stream::Credentials;
//! use librice::candidate::{Candidate, CandidateType, TransportType};
//!
//! let agent = Agent::default();
//! // Configure the agent as you wish.
//! // e.g. add a stun server.
//! // agent.add_stun_server(TransportType::Udp, SocketAddr::new([192, 168, 0, 1], 3478));
//!
//! // Add a stream and component within that stream for data flow.
//! let stream = agent.add_stream();
//! let local_credentials = Credentials::new("luser", "lpass");
//! stream.set_local_credentials(&local_credentials);
//! let component = stream.add_component().unwrap();
//!
//! // At some point you will also need the remote credentials to be able to successfully connect
//! // with the peer. If trickle-ice, then this can occur during candidate gathering, otherwise,
//! // should occur before the remote candidates are added to the agent.
//! let remote_credentials = Credentials::new("ruser", "rpass");
//! stream.set_local_credentials(&remote_credentials);
//!
//! // Retrieve the receive end of a message queue that indicates gathering state, component state,
//! // and other such messages.
//! let mut messages = agent.messages();
//!
//! // start gathering candidates.
//! stream.gather_candidates().await.unwrap();
//!
//! while let Some(msg) = messages.next().await {
//! match msg {
//! AgentMessage::GatheredCandidate(stream, gathered) => {
//! // based on local policy, you can choose to never add the locally gathered
//! // candidate to the stream to avoid using a candidate for connectivity checks later.
//! stream.add_local_gathered_candidate(gathered);
//! // For trickle-ice handling, you would send the gathered candidate to the peer.
//! }
//! AgentMessage::GatheringComplete(component) => {
//! // For non trickle-ice handling, if all relevant components in a stream have
//! // completed gathering, you would retrieve the list of local candidates
//! // and send that to the peer along with any other setup information required.
//! println!("component {} has completed gathering", component.id());
//! let stream = component.stream();
//! for cand in stream.local_candidates() {
//! println!(
//! "stream {} has gathered local candidate {}",
//! stream.id(),
//! cand.to_sdp_string()
//! );
//! }
//! break;
//! }
//! AgentMessage::ComponentStateChange(component, new_state) => {
//! println!("component {} has changed state to {new_state:?}", component.id());
//! },
//! }
//! }
//!
//! // On receiving remote candidates from the peer you would add them to the agent in order to
//! // start connectivity checks.
//! # let remote_host_addr = SocketAddr::new([127, 0, 0, 1].into(), 54321);
//! # let remote_candidate = Candidate::builder(
//! # 1, // component id
//! # CandidateType::Host,
//! # TransportType::Udp,
//! # "0", // foundation
//! # remote_host_addr.into(),
//! # )
//! # .build();
//! stream.add_remote_candidate(&remote_candidate);
//!
//! // Once the complete set of remote candidates have been received, then notify the agent of
//! // this.
//! stream.end_of_remote_candidates();
//!
//! // connectivity checks will progress and either a successful pair (the selected pair) will be
//! // found, or failure will be signaled for the component's connection state.
//! // while let Some(msg) = messages.next().await {
//! // match msg {
//! // ...
//! // }
//! // }
//!
//! // once a selected pair is chosen, data can be received.
//! let recv = component.recv();
//! // and sent
//! component.send([1, 2, 3, 4].as_slice()).await;
//! # };
//! # #[cfg(feature = "runtime-smol")]
//! # smol::block_on(task);
//! # #[cfg(all(not(feature = "runtime-smol"), feature = "runtime-tokio"))]
//! # runtime.block_on(task);
//! ```
// TODO: 0.5.0 remove pub
pub use candidate;
pub use random_string;
pub use ;
pub