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
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
#![warn(missing_docs)]

//! `uflow` is a non-blocking, connection-based layer over UDP that provides an ordered and
//! drop-tolerant packet streaming interface for real-time applications (e.g. games). It manages
//! connection state, packet sequencing, packet fragmentation, reliable delivery, and congestion
//! control to create a simple and robust solution for low-latency internet communication.
//!
//! # Hosting a Server
//!
//! A `uflow` server is created by calling [`Server::bind[...]()`](server::Server::bind), which
//! opens a UDP socket bound to the specified address, and returns a corresponding `Server` object.
//! The number of active connections will be restricted to the configured limit, and each incoming
//! connection will be initialized using the given endpoint configuration (see:
//! [`server::Config`]).
//!
//! ```
//! let server_address = "127.0.0.1:8888";
//! let config = uflow::server::Config {
//!     max_active_connections: 8,
//!     .. Default::default()
//! };
//!
//! // Create a server object
//! let mut server = uflow::server::Server::bind(server_address, config)
//!     .expect("Failed to bind/configure socket");
//! ```
//!
//! As a non-blocking interface, a server object depends on periodic calls to
//! [`Server::step()`](server::Server::step) to process inbound traffic and update connection
//! states. To signal pending events to the application, `step()` returns an iterator to a list of
//! [`server::Event`] objects which contain information specific to each event type.
//!
//! Once a client handshake has been completed, a [`RemoteClient`](server::RemoteClient) object
//! will be created to represent the new connection. These objects may be obtained by calling
//! [`Server::client()`](server::Server::client) with the appropriate address. Because
//! `RemoteClient` does not store user data, it is expected that the application will store
//! any necessary per-client data in a separate data structure.
//!
//! A `RemoteClient` functions as a handle for a given connection, and allows the server
//! application to send packets and query various connection details. However, no packets will be
//! placed on the network, and no received packets will be processed until the next call to
//! `step()`. The application may call [`Server::flush()`](server::Server::flush) to send outbound
//! data immediately.
//!
//! A basic server loop that extends the above example is shown below:
//!
//! ```
//! # let server_address = "127.0.0.1:8888";
//! # let config = Default::default();
//! # let mut server = uflow::server::Server::bind(server_address, config).unwrap();
//! loop {
//!     // Process inbound UDP frames and handle events
//!     for event in server.step() {
//!         match event {
//!             uflow::server::Event::Connect(client_address) => {
//!                 // TODO: Handle client connection
//!             }
//!             uflow::server::Event::Disconnect(client_address) => {
//!                 // TODO: Handle client disconnection
//!             }
//!             uflow::server::Event::Error(client_address, error) => {
//!                 // TODO: Handle connection error
//!             }
//!             uflow::server::Event::Receive(client_address, packet_data) => {
//!                 // Echo the packet on channel 0
//!                 let mut client = server.client(&client_address).unwrap().borrow_mut();
//!                 client.send(packet_data, 0, uflow::SendMode::Unreliable);
//!             }
//!         }
//!     }
//!
//!     // Send data, update server application state
//!     // ...
//!
//!     // Flush outbound data
//!     server.flush();
//!
//!     // Sleep for 30ms (≈33 updates/second)
//!     std::thread::sleep(std::time::Duration::from_millis(30));
//! #   break;
//! }
//! ```
//!
//! See the `echo_server` example for a complete server implementation.
//!
//! # Connecting to a Server
//!
//! A `uflow` client is created by calling [`Client::connect()`](client::Client::connect), which
//! opens a non-blocking UDP socket and returns a corresponding [`Client`](client::Client) object.
//! A connection will be initiated immediately using the provided destination address and
//! configuration (see [`client::Config`]).
//!
//! ```
//! let server_address = "127.0.0.1:8888";
//! let config = Default::default();
//!
//! // Create a client object
//! let mut client = uflow::client::Client::connect(server_address, config)
//!     .expect("Invalid address");
//! ```
//!
//! Like a server, a client depends on periodic calls to [`Client::step()`](client::Client::step)
//! in order to process inbound traffic and update its connection state. A basic client loop which
//! extends the above example is shown below:
//!
//! ```
//! # let server_address = "127.0.0.1:8888";
//! # let config = Default::default();
//! # let mut client = uflow::client::Client::connect(server_address, config).unwrap();
//! loop {
//!     // Process inbound UDP frames
//!     for event in client.step() {
//!         match event {
//!             uflow::client::Event::Connect => {
//!                 // TODO: Handle connection
//!             }
//!             uflow::client::Event::Disconnect => {
//!                 // TODO: Handle disconnection
//!             }
//!             uflow::client::Event::Error(error) => {
//!                 // TODO: Handle connection error
//!             }
//!             uflow::client::Event::Receive(packet_data) => {
//!                 // TODO: Handle received packets
//!             }
//!         }
//!     }
//!
//!     // Send data, update client application state
//!     // ...
//!
//!     // Flush outbound data
//!     client.flush();
//!
//!     // Sleep for 30ms (≈33 updates/second)
//!     std::thread::sleep(std::time::Duration::from_millis(30));
//! #   break;
//! }
//! ```
//!
//! See the `echo_client` example for a complete client implementation.
//!
//! # Sending Packets
//!
//! Packets are sent to a remote host by calling [`client::Client::send()`] or
//! [`server::RemoteClient::send()`], which additionally requires a channel ID and a packet send
//! mode. Any packets that are sent prior to establishing a connection will be sent once the
//! connection succeeds.
//!
//! ```
//! let server_address = "127.0.0.1:8888";
//! let config = Default::default();
//! let mut client = uflow::client::Client::connect(server_address, config).unwrap();
//!
//! let packet_data = "Hello world!".as_bytes();
//! let channel_id = 0;
//! let send_mode = uflow::SendMode::Reliable;
//!
//! client.send(packet_data.into(), channel_id, send_mode);
//! ```
//!
//! Additional details relating to how packets are sent and received by `uflow` are described in
//! the following subsections.
//!
//! ##### Packet Fragmentation and Aggregation
//!
//! Small packets are aggregated into larger UDP frames, and large packets are divided into
//! fragments such that no frame exceeds the internet MTU (1500 bytes). Each fragment is
//! transferred with the same send mode as its containing packet—that is, fragments will be resent
//! if and only if the containing packet is marked with [`SendMode::Persistent`] or
//! [`SendMode::Reliable`]. A packet is considered received once all of its constituent fragments
//! have been received.
//!
//! ##### Channels
//!
//! Each connection contains 64 virtual channels that are used to ensure relative packet ordering:
//! packets that are received on a given channel will be delivered to the receiving application in
//! the order they were sent. Packets which have not yet been received may be skipped, depending on
//! the send mode of the particular packet, and whether or not any subsequent packets have been
//! received.
//!
//! Because packets that are sent using [`SendMode::Reliable`] may not be skipped, and because all
//! packets on a given channel must be delivered in-order, the receiving application will not see a
//! given received packet until all previous reliable packets on the same channel have also been
//! received. This means that if a reliable packet is dropped, that channel will effectively stall
//! for its arrival, but packets received on other channels may still be delivered in the meantime.
//!
//! Thus, by carefully choosing the send mode and channel of outgoing packets, the latency effects
//! of intermittent network losses can be mitigated. Because `uflow` does not store packets by
//! channel, and otherwise never iterates over the space of channel IDs, there is no penalty to
//! using a large number of channels.
//!
//! ##### Packet Buffering
//!
//! All packets are sent subject to adaptive rate control, a maximum transfer window, and a memory
//! limit set by the receiving host. If any of these mechanisms prevent a packet from being sent,
//! the packet will remain in a queue at the sender. Thus, a sender can expect that packets will
//! begin to accumulate in its queue if the connection bandwidth is low, or if the receiver is not
//! processing packets quickly enough.
//!
//! The total size of all packets awaiting delivery can be obtained by calling
//! [`Client::send_buffer_size()`](client::Client::send_buffer_size) or
//! [`RemoteClient::send_buffer_size()`](server::RemoteClient::send_buffer_size), and if desired,
//! an application can use this value to terminate excessively delayed connections. In addition,
//! the application may send packets using [`SendMode::TimeSensitive`] to drop packets at the
//! sender if they could not be sent immediately (i.e. during the next call to `step()`). In the
//! event that the total available bandwidth is limited, this prevents outdated packets from using
//! any unnecessary bandwidth, and prioritizes sending newer packets in the send queue.
//!
//! # Receiving Packets (and Other Events)
//!
//! Each time `step()` is called on a `Client` or `Server` object, connection events are returned
//! via iterator. Because servers may have multiple connections, server events each contain an
//! associated client address, whereas client events do not. See [`client::Event`] and
//! [`server::Event`] for more details.
//!
//! For client and server, the overall connection-event behavior is as follows. A `Connect` event
//! will be generated when a connection is first established. If either end of the connection
//! explicitly disconnects, a `Disconnect` event will be generated. Once a packet has been received
//! (and that packet is not waiting for any previous packets), a `Receive` event will be generated.
//! If an error is encountered, or the connection times out at any point, an `Error` event will be
//! generated. No further events are generated after a `Disconnect` or an `Error` event.
//!
//! ##### Maximum Receive Allocation
//!
//! If a sender is sending a continuous stream of packets, but `step()` is not called on the
//! receiver for whatever reason, the number of packets in the receiver's receive buffer will
//! increase until its [maximum receive allocation](EndpointConfig#structfield.max_receive_alloc)
//! has been reached. At that point, any new packets will be silently ignored.
//!
//! *Note*: This feature is intended to prevent memory allocation attacks. A well-behaved sender
//! will ensure that it does not send new packets which would exceed the receiver's memory limit,
//! and the stall will back-propagate accordingly.
//!
//! ##### Optimal Acknowledgements
//!
//! If desired, an application may call `flush()` on the associated client or server object
//! immediately after all events from `step()` have been handled. By doing so, information relating
//! to which packets have been delivered (and how much buffer space is available) will be relayed
//! back to the sender as soon as possible.
//!
//! # Disconnecting
//!
//! A connection is explicitly closed by calling `disconnect()` or `disconnect_now()` on the
//! corresponding [`Client`](client::Client) or [`RemoteClient`](server::RemoteClient) object;
//! `disconnect()` will make sure to send all pending outbound packets prior to disconnecting,
//! whereas `disconnect_now()` will initiate the disconnection process on the next call to
//! `step()`. In both cases the application must continue to call `step()` to ensure that the
//! disconnection takes place.
//!
//! ```
//! # let server_address = "127.0.0.1:8888";
//! # let config = Default::default();
//! # let mut client = uflow::client::Client::connect(server_address, config).unwrap();
//! client.disconnect();
//!
//! // ... calls to client.step() continue
//! ```
//!
//! Servers may also call [`Server::drop()`](server::Server::drop), which sends no further packets
//! and forgets the connection immediately. This will generate a timeout error on the client.

mod half_connection;
mod frame;
mod packet_id;
mod udp_frame_sink;

/// Server-related connection objects and parameters.
pub mod server;

/// Client-related connection objects and parameters.
pub mod client;

/// The current protocol version ID.
pub const PROTOCOL_VERSION: u8 = 3;

/// The maximum number of channels which may be used on a given connection.
pub const CHANNEL_COUNT: usize = frame::serial::MAX_CHANNELS;

/// The maximum size of the frame transfer window, in sequence IDs.
pub const MAX_FRAME_WINDOW_SIZE: u32 = 4096;

/// The maximum size of the packet transfer window, in sequence IDs.
pub const MAX_PACKET_WINDOW_SIZE: u32 = 4096;

/// The common maximum transfer unit (MTU) of the internet.
pub const INTERNET_MTU: usize = 1500;

/// The number of bytes in a UDP header (including the IP header).
pub const UDP_HEADER_SIZE: usize = 28;

/// The maximum size of a `uflow` frame in bytes, according to the internet MTU and UDP header
/// size.
pub const MAX_FRAME_SIZE: usize = INTERNET_MTU - UDP_HEADER_SIZE;

/// The maximum size of a packet fragment in bytes, according to frame serialization overhead.
pub const MAX_FRAGMENT_SIZE: usize = MAX_FRAME_SIZE - frame::serial::DATA_FRAME_OVERHEAD - frame::serial::MAX_DATAGRAM_OVERHEAD;

/// The absolute maximum size of a packet, in bytes.
pub const MAX_PACKET_SIZE: usize = MAX_FRAGMENT_SIZE * frame::serial::MAX_FRAGMENTS;

/// A mode by which a packet is sent.
#[derive(Clone,Copy,Debug,PartialEq)]
pub enum SendMode {
    /// This packet will be sent at most once. If this packet cannot be sent immediately (i.e.
    /// prior to the next call to [`Client::step`](client::Client::step) or
    /// [`Server::step`](server::Server::step)), it will be discarded by the sender. If this packet
    /// has not been received, but a subsequent packet has been received on the same channel, the
    /// receiver may skip this packet.
    TimeSensitive,
    /// This packet will be sent exactly once. If this packet has not been received, but a
    /// subsequent packet has been received on the same channel, the receiver may skip this packet.
    Unreliable,
    /// This packet will be sent and resent until acknowledged by the receiver. If this packet has
    /// not been received, but a subsequent packet has been received on the same channel, the
    /// receiver may skip this packet.
    ///
    /// *Note:* The packet will cease to be resent once the sender has detected a skip.
    Persistent,
    /// This packet will be sent until acknowledged by the receiver. The receiver will not deliver
    /// subsequent packets on the same channel until this packet has been delivered.
    Reliable,
}

/// Parameters used to configure either endpoint of a `uflow` connection.
#[derive(Clone,Debug)]
pub struct EndpointConfig {
    /// The maximum send rate, in bytes per second. The endpoint will ensure that its outgoing
    /// bandwidth does not exceed this value.
    ///
    /// Must be greater than 0. Values larger than 2^32 will be truncated.
    pub max_send_rate: usize,

    /// The maximum acceptable receive rate, in bytes per second. The opposing endpoint will ensure
    /// that its outgoing bandwidth does not exceed this value.
    ///
    /// Must be greater than 0. Values larger than 2^32 will be truncated.
    pub max_receive_rate: usize,

    /// The maximum size of a sent packet, in bytes. The endpoint will ensure that it does not send
    /// packets with a size exceeding this value.
    ///
    /// Must be greater than 0, and less than or equal to [`MAX_PACKET_SIZE`].
    pub max_packet_size: usize,

    /// The maximum allocation size of the endpoint's receive buffer, in bytes. The endpoint will
    /// ensure that the total amount of memory allocated to receive packet data doesn't exceed this
    /// value, rounded up to the nearest multiple of
    /// [`MAX_FRAGMENT_SIZE`](crate::MAX_FRAGMENT_SIZE).
    ///
    /// Must be greater than 0.
    ///
    /// *Note*: The maximum allocation size necessarily constrains the maximum receivable packet
    /// size. A connection attempt will fail if the `max_packet_size` of the opposing endpoint
    /// exceeds this value.
    pub max_receive_alloc: usize,

    // TODO (0.8.0): Combine keepalive and keepalive_interval_ms into Option<u64>

    /// Whether the endpoint should automatically send keepalive frames if no data has been sent
    /// for one keepalive interval (see `keepalive_interval_ms`). If set to false, one endpoint
    /// must continually send data to avoid causing a timeout on the opposite host.
    pub keepalive: bool,

    /// The interval in milliseconds at which keepalive frames are sent.
    ///
    /// *Note*: Keepalive frames will not be sent faster than the connection RTO (computed
    /// according to TFRC) or 2s, whichever is longer.
    pub keepalive_interval_ms: u64,

    /// Time in milliseconds after which an active connection will terminate if no frames have been
    /// received from the remote endpoint.
    pub active_timeout_ms: u64,
}

impl Default for EndpointConfig {
    /// Creates an endpoint configuration with the following parameters:
    ///   * Maximum outgoing bandwidth: 2MB/s
    ///   * Maximum incoming bandwidth: 2MB/s
    ///   * Maximum packet size: 1MB
    ///   * Maximum packet receive allocation: 1MB
    ///   * Keepalive: true
    ///   * Keepalive interval: 5s
    ///   * Active timeout: 20s
    fn default() -> Self {
        Self {
            max_send_rate: 2_000_000,
            max_receive_rate: 2_000_000,

            max_packet_size: 1_000_000,
            max_receive_alloc: 1_000_000,

            keepalive: true,
            keepalive_interval_ms: 5000,

            active_timeout_ms: 20000
        }
    }
}

impl EndpointConfig {
    /// Returns `true` if each parameter has a valid value.
    pub fn is_valid(&self) -> bool {
        self.max_send_rate > 0 &&
        self.max_receive_rate > 0 &&
        self.max_packet_size > 0 &&
        self.max_packet_size <= MAX_PACKET_SIZE &&
        self.max_receive_alloc > 0
    }
}