diff --git a/src/codec/frame.rs b/src/codec/frame.rs index 941706d..e8abf50 100644 --- a/src/codec/frame.rs +++ b/src/codec/frame.rs @@ -12,14 +12,31 @@ use super::AsyncSocket; use crate::packet::connected::{FramesMut, FramesRef}; use crate::packet::{unconnected, Packet}; +/// `Framed` is a base structure for socket communication. +/// In this project, it wraps an asynchronous UDP socket and implements the +/// [`Stream`](futures::stream::Stream) and [`Sink`](futures::sink::Sink) traits. +/// This allows for reading and writing RakNet frames over the socket. +/// It supports both receiving and sending unconnected and connected packets. pub(crate) struct Framed { + /// The underlying socket that is being wrapped. socket: T, + /// [maximum transmission unit](https://en.wikipedia.org/wiki/Maximum_transmission_unit), + /// used to pre-allocate the capacity for both the `rd` and `wr` byte buffers max_mtu: usize, + /// a buffer for storing incoming data read from the socket. rd: BytesMut, + /// a buffer for writing bytes wr: BytesMut, + /// the socket address to which the data will be sent out_addr: SocketAddr, + /// indicates whether the data has been sent to the peer, and the + /// `wr` buffer has been cleared flushed: bool, + /// indicates whether data has been read from the peer and written + /// into the `rd` buffer. When `true`, it signifies that the data is ready for frame packet + /// decoding and will be passed to the upper layer for further processing. is_readable: bool, + /// the address of the current peer current_addr: Option, decode_span: Option, read_span: Option, diff --git a/src/lib.rs b/src/lib.rs index 3cb1faa..69e5c17 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -58,6 +58,9 @@ use std::net::SocketAddr; use bytes::Bytes; +/// The `Role` enum is used to identify the `Client` and `Server`, and it stores their GUID. +/// The GUID is a globally unique identifier that is not affected by changes to IP address or port. +/// It is application-defined and ensures unique identification. #[derive(Debug, Clone, Copy)] enum Role { Client { guid: u64 }, diff --git a/src/link.rs b/src/link.rs index bb2db37..c75b278 100644 --- a/src/link.rs +++ b/src/link.rs @@ -17,17 +17,30 @@ use crate::{Peer, Role}; /// Shared link between stream and sink pub(crate) type SharedLink = Arc; -/// Transfer data and task between stream and sink. +/// The `TransferLink` is an visitor structure that temporarily holds various types of transfer +/// link data, such as received `AckOrNack`, sequences of pending response sequence numbers, and +/// packets ready to send like `unconnected::Packet` and `FrameBody`. +/// It provides methods for compressing sequence numbers into `AckOrNack` as well as access to other +/// data within the link. pub(crate) struct TransferLink { - // incoming ack with receive timestamp + /// incoming ack with receive timestamp incoming_ack: ConcurrentQueue<(AckOrNack, Instant)>, + /// incoming Nack packet. incoming_nack: ConcurrentQueue, + /// the flag is set to `true` when the `OutgoingGuard` is closed, + /// and there are still reliable packets awaiting ACK (needing resend). + /// In this state, the close operation will sleep until an ACK is received to wake it, + /// after which the flag will be reset to `false`. forward_waking: AtomicBool, + /// pending ACK packets to be sent. outgoing_ack: parking_lot::Mutex>>, + /// pending NACK packets to be sent. outgoing_nack: parking_lot::Mutex>>, + /// data related to unconnected packets awaiting processing. unconnected: ConcurrentQueue, + /// data for the frame body that is yet to be handled. frame_body: ConcurrentQueue, role: Role, @@ -173,11 +186,15 @@ impl TransferLink { } } -/// A route for incoming packets +/// `Route` is an intermediary structure that wraps a `TransferLink`, providing the functionality to +/// `deliver` different types of data frames. pub(crate) struct Route { + /// `Route` create an asynchronous channel, splitting it into a sender and a + /// receiver, with the receiver being returned in the `new` method. This is the sender part + /// of the asynchronous channel. router_tx: Sender>, link: SharedLink, - // the next expected sequence number + // the next expected sequence number for incoming frames on this route seq_read: u24, } diff --git a/src/packet/connected/ack.rs b/src/packet/connected/ack.rs index 878f7dc..55a2494 100644 --- a/src/packet/connected/ack.rs +++ b/src/packet/connected/ack.rs @@ -30,7 +30,12 @@ impl std::fmt::Debug for AckOrNack { } impl AckOrNack { - /// Extend a packet from a sorted sequence numbers iterator based on mtu. + /// This function implements **Sequence Number Compression** on an `Iterator`. Consecutive + /// sequence numbers are grouped into `Record::Range`, while non-consecutive sequence + /// numbers are stored as `Record::Single`. This approach reduces the data payload size. + /// + /// - A `Record::Range` consumes 7 bytes. + /// - A `Record::Single` consumes 4 bytes. pub(crate) fn extend_from>( mut sorted_seq_nums: I, mut mtu: u16, diff --git a/src/server/handler/offline.rs b/src/server/handler/offline.rs index 6f92182..0220840 100644 --- a/src/server/handler/offline.rs +++ b/src/server/handler/offline.rs @@ -27,6 +27,13 @@ pub(crate) struct Config { pub(crate) max_pending: usize, } +/// Implements a simple `OfflineHandler` state machine to process sink requests. +/// - When in the `Listening` state, no additional processing is done. +/// - When in the `SendingPrepare` state, the enum holds the packet to be sent and the target +/// address. It will call the underlying `Framed::poll_ready` and `Framed::start_send` to prepare +/// and send the data. After that, the state is set to `SendingFlush`. +/// - When in the `SendingFlush` state, it calls the underlying `Framed::poll_flush` to flush the +/// data and then resets the state back to `Listening`. enum OfflineState { Listening, SendingPrepare(Option<(unconnected::Packet, SocketAddr)>), @@ -34,13 +41,28 @@ enum OfflineState { } pin_project! { - /// OfflineHandler takes the codec frame and perform offline handshake. + /// `OfflineHandler` is a server handler that implements the RakNet offline handshake protocol. + /// It acts as an upper layer processor for [`Framed`](crate::codec::frame::Framed). + /// `OfflineHandler` implements the [`Stream`](futures::stream::Stream) interface and handles the responses + /// for data packets such as `UnconnectedPing`, `OpenConnectionRequest1`, and + /// `OpenConnectionRequest2`. For the specific protocol sequence, please refer to + /// [RakNet Protocol Documentation](https://github.com/vp817/RakNetProtocolDoc?tab=readme-ov-file#server). pub(crate) struct OfflineHandler { #[pin] + // [`Framed`](crate::codec::frame::Framed) is responsible for decoding raw data + // from the UDP socket into RakNet frames. frame: F, + // stores various transmission configurations, specifically refer in [`Config`]. config: Config, - // Half-connected queue + // A half-connected queue implemented using [`lru::LruCache`]. + // At this point, the connection is in the OpenConnectionRequest1 stage, + // and it will be popped out during the OpenConnectionRequest2 + // or when the connection is disconnected. pending: lru::LruCache, + // A `HashMap` that caches connections + // in the OpenConnectionRequest2 stage and is cleaned up on disconnection. + // The `connected` map is used to check if a `Peer` has completed the connection + // from the socket. connected: HashMap, state: OfflineState, role: Role,