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
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
//Media Enhanced Swiftlet Quic Rust Library for Real-time Internet Communications
//MIT License
//Copyright (c) 2024 Jared Loewenthal
//
//Permission is hereby granted, free of charge, to any person obtaining a copy
//of this software and associated documentation files (the "Software"), to deal
//in the Software without restriction, including without limitation the rights
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//copies of the Software, and to permit persons to whom the Software is
//furnished to do so, subject to the following conditions:
//
//The above copyright notice and this permission notice shall be included in all
//copies or substantial portions of the Software.
//
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
//SOFTWARE.

#![deny(missing_docs)]

//! Providing real-time internet communications using the QUIC protocol!
//!
//! Using this QUIC swiftlet sub-library makes it easy to create a single-threaded QUIC endpoint
//! (server or client) and run an application protocol in response to various events. Both reliable
//! (time-insensitive) and unreliable (real-time communication) messages are possible to be sent and
//! received using this library.

/// QUIC Endpoint Module
pub mod endpoint;
use endpoint::{
    ConnectionEndReason, ConnectionId, Endpoint, Error, NextEvent, ReadInfo, RecvEvent,
};

use std::time::{Duration, Instant};

/// Required QUIC Endpoint Handler Event Callback Functions
///
/// These functions will get called for their respective events.
/// These callbacks are expected to return within a couple milliseconds AT THE MOST
/// for all processing cases.
pub trait EndpointEventCallbacks {
    /// Called when a new connection is started and is application ready.
    fn connection_started(&mut self, endpoint: &mut Endpoint, cid: &ConnectionId);

    /// Called when a connection has ended and should be cleaned up.
    ///
    /// Return true if you want the Endpoint Handler event loop to exit.
    /// The event loop will return an Ok(true) indicating that the connection_ended callback function caused the exit.
    /// This is intended to be useful in case the application wants to start up the Endpoint Handler event loop again.
    fn connection_ended(
        &mut self,
        endpoint: &mut Endpoint,
        cid: &ConnectionId,
        reason: ConnectionEndReason,
        remaining_connections: usize,
    ) -> bool;

    /// Called when a connection is in the process of ending and allows an application to clean up
    /// relevant states earlier before the connection fully ends.
    ///
    /// By default, this function does nothing when called.
    fn connection_ending_warning(
        &mut self,
        _endpoint: &mut Endpoint,
        _cid: &ConnectionId,
        _reason: ConnectionEndReason,
    ) {
        // Do nothing by default
    }

    /// Called when the next tick occurrs based on the tick duration given to the run_event_loop call.
    ///
    /// Return true if you want the Endpoint Handler event loop to exit.
    /// The event loop will return an Ok(false) indicating that the tick callback function caused the exit.
    fn tick(&mut self, endpoint: &mut Endpoint) -> bool;

    /// Called when there is something to read on the main stream.
    ///
    /// The main stream is a reliable (ordered) stream that focuses on communicating
    /// high-priority, small(ish) messages between the server and client.
    ///
    /// The read_data length will be the number of bytes asked for on the previous call.
    /// The first time it is called the length will be the number of bytes set by the Endpoint Config
    /// (initial_main_recv_size). This data can be processed based on the application protocol.
    ///
    /// Return the number of bytes you want to read the next time this callback is called.
    /// If the optional usize value is set to zero (0) it will be interpreted as the Endpoint Config
    /// initial_main_recv_size value.
    /// Returning a None will close the main stream but since the main stream is required,
    /// the connection will start the close process.
    fn main_stream_recv(
        &mut self,
        endpoint: &mut Endpoint,
        cid: &ConnectionId,
        read_data: &[u8],
    ) -> Option<usize>; // Just a usize in future where 0 represents close the stream...?

    /// Called when there is something to read on the real-time stream.
    ///
    /// The real-time "stream" is different than the main stream because it uses multiple
    /// incremental QUIC unidirectional streams in the backend where each stream id represents
    /// a single time segment that has unreliability the moment when the next single time segment
    /// arrives before the previous stream had finished.
    ///
    /// The read_data length will be the number of bytes asked for on the previous call.
    /// The first time it is called the length will be the number of bytes set by the Endpoint Config
    /// (initial_rt_recv_size). This data can be processed based on the application protocol.
    ///
    /// Return the number of bytes you want to read the next time this callback is called.
    /// If the usize value is set to zero (0) it will be interpreted as waiting for the next finished
    /// real-time stream.
    ///
    /// By default, this function will return 0, which translates to waiting for the next finished
    /// real-time stream as indicated above. This function should be overwritten in order to handle
    /// processing real-time stream data.
    fn rt_stream_recv(
        &mut self,
        _endpoint: &mut Endpoint,
        _cid: &ConnectionId,
        _read_data: &[u8],
        _rt_id: u64,
    ) -> usize {
        0
    }

    /// Called when there is something to read on the background stream.
    ///
    /// The background stream is a reliable (ordered) stream that focuses on communicating
    /// large(ish) messages between the server and client such as a file transfer.
    ///
    /// The read_data length will be the number of bytes asked for on the previous call.
    /// The first time it is called the length will be the number of bytes set by the Endpoint Config
    /// (initial_background_recv_size). This data can be processed based on the application protocol.
    ///
    /// Return the number of bytes you want to read the next time this callback is called.
    /// If the optional usize value is set to zero (0) it will be interpreted as the as the Endpoint Config
    /// initial_background_recv_size value.
    /// Returning a None will close the background stream but since the background stream is required,
    /// the connection will start the close process.
    ///
    /// By default, this function will return None, which translates to a connection closure as indicated above.
    /// This function should be overwritten to handle cases where a connection might send
    /// information over the background stream to prevent accidental connection closures.
    fn background_stream_recv(
        &mut self,
        _endpoint: &mut Endpoint,
        _cid: &ConnectionId,
        _read_data: &[u8],
    ) -> Option<usize> {
        // Return None by default since the background stream is not managed
        None
    }
}

/// Main library structure that handles the QUIC Endpoint
pub struct EndpointHandler<'a> {
    current_tick: u64,
    endpoint: &'a mut Endpoint,
    events: &'a mut dyn EndpointEventCallbacks,
}

impl<'a> EndpointHandler<'a> {
    /// Create a QUIC Endpoint Handler by giving it an already created Endpoint
    /// and a mutable reference of a structure that implements the Endpoint Event Callbacks trait.
    pub fn new(endpoint: &'a mut Endpoint, events: &'a mut dyn EndpointEventCallbacks) -> Self {
        EndpointHandler {
            current_tick: 0,
            endpoint,
            events,
        }
    }

    /// QUIC Endpoint Handler Event Loop
    ///
    /// Allows the endpoint handler to take control of the thread!
    ///
    /// Communicates with the application code with the previously passed event callbacks
    ///
    /// Tick "0" callback will happen immediately
    ///
    /// Returns true if this event loop function should be maybe called again
    ///  (ie. run a client endpoint in "low power" mode when it has no connections)
    pub fn run_event_loop(&mut self, tick_duration: Duration) -> Result<bool, Error> {
        let start_instant = Instant::now();
        let mut next_tick_instant = start_instant;

        loop {
            // This function will sleep the thread while waiting for the next instant or recv udp data
            match self.endpoint.get_next_event(next_tick_instant)? {
                NextEvent::ReceivedData => {
                    if self.run_recv_loop()? {
                        return Ok(true);
                    }
                }
                NextEvent::Tick => {
                    next_tick_instant += tick_duration; // Does not currently check for skipped ticks / assumes computer processes all
                    self.current_tick += 1;

                    if self.events.tick(self.endpoint) {
                        return Ok(false);
                    }
                }
                NextEvent::ConnectionEnded((cid, reason)) => {
                    let remaining_connections = self.endpoint.get_num_connections();
                    if self.events.connection_ended(
                        self.endpoint,
                        &cid,
                        reason,
                        remaining_connections,
                    ) {
                        return Ok(true);
                    }
                }
                NextEvent::ConnectionEnding((cid, reason)) => {
                    self.events
                        .connection_ending_warning(self.endpoint, &cid, reason);
                }
                NextEvent::AlreadyHandled => {
                    // Do Nothing and try to call get_next_event ASAP
                }
            }
        }
    }

    fn run_recv_loop(&mut self) -> Result<bool, Error> {
        loop {
            match self.endpoint.recv()? {
                RecvEvent::DoneReceiving => {
                    return Ok(false);
                }
                RecvEvent::MainStreamReceived((cid, verified_index, mut data_vec, mut len)) => {
                    loop {
                        let target_len_opt =
                            self.events
                                .main_stream_recv(self.endpoint, &cid, &data_vec[..len]);
                        match self.endpoint.main_stream_read(
                            verified_index,
                            data_vec,
                            target_len_opt,
                        )? {
                            ReadInfo::ReadData((new_data_vec, new_len)) => {
                                data_vec = new_data_vec;
                                len = new_len;
                            }
                            ReadInfo::DoneReceiving => {
                                break;
                            }
                            ReadInfo::ConnectionEnded(reason) => {
                                let remaining_connections = self.endpoint.get_num_connections();
                                if self.events.connection_ended(
                                    self.endpoint,
                                    &cid,
                                    reason,
                                    remaining_connections,
                                ) {
                                    return Ok(true);
                                }
                                break;
                            }
                            ReadInfo::ConnectionEnding(reason) => {
                                self.events
                                    .connection_ending_warning(self.endpoint, &cid, reason);
                                break;
                            }
                        }
                    }
                }
                RecvEvent::RealtimeReceived(cid, verified_index, mut data_vec, mut len, rt_id) => {
                    loop {
                        let target_len = self.events.rt_stream_recv(
                            self.endpoint,
                            &cid,
                            &data_vec[..len],
                            rt_id,
                        );
                        match self
                            .endpoint
                            .rt_stream_read(verified_index, data_vec, target_len)?
                        {
                            Some((new_data_vec, new_len)) => {
                                data_vec = new_data_vec;
                                len = new_len;
                            }
                            None => {
                                break;
                            }
                        }
                    }
                }
                RecvEvent::BackgroundStreamReceived((
                    cid,
                    verified_index,
                    mut data_vec,
                    mut len,
                )) => loop {
                    let target_len_opt =
                        self.events
                            .background_stream_recv(self.endpoint, &cid, &data_vec[..len]);
                    match self.endpoint.background_stream_read(
                        verified_index,
                        data_vec,
                        target_len_opt,
                    )? {
                        ReadInfo::ReadData((new_data_vec, new_len)) => {
                            data_vec = new_data_vec;
                            len = new_len;
                        }
                        ReadInfo::DoneReceiving => {
                            break;
                        }
                        ReadInfo::ConnectionEnded(reason) => {
                            let remaining_connections = self.endpoint.get_num_connections();
                            if self.events.connection_ended(
                                self.endpoint,
                                &cid,
                                reason,
                                remaining_connections,
                            ) {
                                return Ok(true);
                            }
                            break;
                        }
                        ReadInfo::ConnectionEnding(reason) => {
                            self.events
                                .connection_ending_warning(self.endpoint, &cid, reason);
                            break;
                        }
                    }
                },
                RecvEvent::ConnectionEnded((cid, reason)) => {
                    let remaining_connections = self.endpoint.get_num_connections();
                    if self.events.connection_ended(
                        self.endpoint,
                        &cid,
                        reason,
                        remaining_connections,
                    ) {
                        return Ok(true);
                    }
                }
                RecvEvent::ConnectionEnding((cid, reason)) => {
                    self.events
                        .connection_ending_warning(self.endpoint, &cid, reason);
                }
                RecvEvent::EstablishedOnce(cid) => {
                    self.events.connection_started(self.endpoint, &cid);
                }
                RecvEvent::NoUpdate => {
                    // Do nothing and call recv again
                }
            }
        }
    }
}