1use bytes::BytesMut;
2use shared::error::*;
3use std::collections::{HashMap, VecDeque};
4use std::io::BufReader;
5use std::net::SocketAddr;
6use std::ops::Add;
7use std::time::{Duration, Instant};
8
9use crate::agent::*;
10use crate::message::*;
11use shared::{TaggedBytesMut, TransportContext, TransportMessage, TransportProtocol};
12
13const DEFAULT_TIMEOUT_RATE: Duration = Duration::from_millis(5);
14const DEFAULT_RTO: Duration = Duration::from_millis(300);
15const DEFAULT_MAX_ATTEMPTS: u32 = 7;
16const DEFAULT_MAX_BUFFER_SIZE: usize = 8;
17
18#[derive(Debug, Clone)]
23pub struct ClientTransaction {
24 id: TransactionId,
25 attempt: u32,
26 start: Instant,
27 rto: Duration,
28 raw: Vec<u8>,
29}
30
31impl ClientTransaction {
32 pub(crate) fn next_timeout(&self, now: Instant) -> Instant {
33 now.add((self.attempt + 1) * self.rto)
34 }
35}
36
37struct ClientSettings {
38 buffer_size: usize,
39 rto: Duration,
40 rto_rate: Duration,
41 max_attempts: u32,
42 closed: bool,
43}
44
45impl Default for ClientSettings {
46 fn default() -> Self {
47 ClientSettings {
48 buffer_size: DEFAULT_MAX_BUFFER_SIZE,
49 rto: DEFAULT_RTO,
50 rto_rate: DEFAULT_TIMEOUT_RATE,
51 max_attempts: DEFAULT_MAX_ATTEMPTS,
52 closed: false,
53 }
54 }
55}
56
57#[derive(Default)]
58pub struct ClientBuilder {
59 settings: ClientSettings,
60}
61
62impl ClientBuilder {
63 pub fn with_rto(mut self, rto: Duration) -> Self {
65 self.settings.rto = rto;
66 self
67 }
68
69 pub fn with_timeout_rate(mut self, d: Duration) -> Self {
71 self.settings.rto_rate = d;
72 self
73 }
74
75 pub fn with_buffer_size(mut self, buffer_size: usize) -> Self {
77 self.settings.buffer_size = buffer_size;
78 self
79 }
80
81 pub fn with_no_retransmit(mut self) -> Self {
86 self.settings.max_attempts = 0;
87 if self.settings.rto == Duration::from_secs(0) {
88 self.settings.rto = DEFAULT_MAX_ATTEMPTS * DEFAULT_RTO;
89 }
90 self
91 }
92
93 pub fn new() -> Self {
94 ClientBuilder {
95 settings: ClientSettings::default(),
96 }
97 }
98
99 pub fn build(
100 self,
101 local: SocketAddr,
102 remote: SocketAddr,
103 protocol: TransportProtocol,
104 ) -> Result<Client> {
105 Ok(Client::new(local, remote, protocol, self.settings))
106 }
107}
108
109pub struct Client {
111 local: SocketAddr,
112 remote: SocketAddr,
113 transport_protocol: TransportProtocol,
114 agent: Agent,
115 settings: ClientSettings,
116 transactions: HashMap<TransactionId, ClientTransaction>,
117 transmits: VecDeque<TransportMessage<BytesMut>>,
118}
119
120impl Client {
121 fn new(
122 local: SocketAddr,
123 remote: SocketAddr,
124 transport_protocol: TransportProtocol,
125 settings: ClientSettings,
126 ) -> Self {
127 Self {
128 local,
129 remote,
130 transport_protocol,
131 agent: Agent::new(),
132 settings,
133 transactions: HashMap::new(),
134 transmits: VecDeque::new(),
135 }
136 }
137
138 pub fn local_addr(&self) -> SocketAddr {
139 self.local
140 }
141
142 pub fn peer_addr(&self) -> SocketAddr {
143 self.remote
144 }
145}
146
147impl sansio::Protocol<TaggedBytesMut, Message, ()> for Client {
148 type Rout = ();
149 type Wout = TaggedBytesMut;
150 type Eout = StunEvent;
151 type Error = Error;
152 type Time = Instant;
153
154 fn handle_read(&mut self, msg: TaggedBytesMut) -> Result<()> {
155 let mut stun_msg = Message::new();
156 let mut reader = BufReader::new(&msg.message[..]);
157 stun_msg.read_from(&mut reader)?;
158 self.agent.handle_event(ClientAgent::Process(stun_msg))
159 }
160
161 fn poll_read(&mut self) -> Option<Self::Rout> {
162 None
163 }
164
165 fn handle_write(&mut self, m: Message) -> Result<()> {
166 if self.settings.closed {
167 return Err(Error::ErrClientClosed);
168 }
169
170 let payload = BytesMut::from(&m.raw[..]);
171
172 let ct = ClientTransaction {
173 id: m.transaction_id,
174 attempt: 0,
175 start: Instant::now(),
176 rto: self.settings.rto,
177 raw: m.raw,
178 };
179 let deadline = ct.next_timeout(ct.start);
180 self.transactions.entry(ct.id).or_insert(ct);
181 self.agent
182 .handle_event(ClientAgent::Start(m.transaction_id, deadline))?;
183
184 self.transmits.push_back(TransportMessage {
185 now: Instant::now(),
186 transport: TransportContext {
187 local_addr: self.local,
188 peer_addr: self.remote,
189 ecn: None,
190 transport_protocol: self.transport_protocol,
191 },
192 message: payload,
193 });
194
195 Ok(())
196 }
197
198 fn poll_write(&mut self) -> Option<Self::Wout> {
206 self.transmits.pop_front()
207 }
208
209 fn poll_event(&mut self) -> Option<Self::Eout> {
210 while let Some(event) = self.agent.poll_event() {
211 let mut ct = if self.transactions.contains_key(&event.id) {
212 self.transactions.remove(&event.id).unwrap()
213 } else {
214 continue;
215 };
216
217 if let StunEvent::Message(_) = &event.evt {
218 return Some(event.evt);
219 }
220 if ct.attempt >= self.settings.max_attempts {
221 return Some(event.evt);
222 }
223
224 ct.attempt += 1;
226
227 let payload = BytesMut::from(&ct.raw[..]);
228 let timeout = ct.next_timeout(Instant::now());
229 let id = ct.id;
230
231 self.transactions.entry(ct.id).or_insert(ct);
233
234 if self
236 .agent
237 .handle_event(ClientAgent::Start(id, timeout))
238 .is_err()
239 {
240 self.transactions.remove(&id);
241 return Some(event.evt);
242 }
243
244 self.transmits.push_back(TransportMessage {
246 now: Instant::now(),
247 transport: TransportContext {
248 local_addr: self.local,
249 peer_addr: self.remote,
250 ecn: None,
251 transport_protocol: self.transport_protocol,
252 },
253 message: payload,
254 });
255 }
256
257 None
258 }
259
260 fn poll_timeout(&mut self) -> Option<Self::Time> {
261 self.agent.poll_timeout()
262 }
263
264 fn handle_timeout(&mut self, now: Instant) -> Result<()> {
265 self.agent.handle_event(ClientAgent::Collect(now))
266 }
267
268 fn close(&mut self) -> Result<()> {
269 if self.settings.closed {
270 return Err(Error::ErrClientClosed);
271 }
272 self.settings.closed = true;
273 self.agent.handle_event(ClientAgent::Close)
274 }
275}