Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

docs: add some docs #7

Merged
merged 6 commits into from
Sep 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions src/codec/frame.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<T> {
/// 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<SocketAddr>,
decode_span: Option<Span>,
read_span: Option<Span>,
Expand Down
3 changes: 3 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 },
Expand Down
25 changes: 21 additions & 4 deletions src/link.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,30 @@ use crate::{Peer, Role};
/// Shared link between stream and sink
pub(crate) type SharedLink = Arc<TransferLink>;

/// 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<AckOrNack>,
/// 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<BinaryHeap<Reverse<u24>>>,
/// pending NACK packets to be sent.
outgoing_nack: parking_lot::Mutex<BTreeSet<Reverse<u24>>>,

/// data related to unconnected packets awaiting processing.
unconnected: ConcurrentQueue<unconnected::Packet>,
/// data for the frame body that is yet to be handled.
frame_body: ConcurrentQueue<FrameBody>,

role: Role,
Expand Down Expand Up @@ -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<FrameSet<FramesMut>>,
link: SharedLink,
// the next expected sequence number
// the next expected sequence number for incoming frames on this route
seq_read: u24,
}

Expand Down
7 changes: 6 additions & 1 deletion src/packet/connected/ack.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<u24>`. 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<I: Iterator<Item = u24>>(
mut sorted_seq_nums: I,
mut mtu: u16,
Expand Down
26 changes: 24 additions & 2 deletions src/server/handler/offline.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,20 +27,42 @@ 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)>),
SendingFlush,
}

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<F> {
#[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<SocketAddr, u8>,
// A `HashMap<SocketAddr, Peer>` 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<SocketAddr, Peer>,
state: OfflineState,
role: Role,
Expand Down
Loading