rak_rs/protocol/packet/
offline.rs

1//!  Offline packets are packets that are sent before a connection is established.
2//! In rak-rs, these packets consist of:
3//! - [`UnconnectedPing`]
4//! - [`UnconnectedPong`]
5//! - [`OpenConnectRequest`]
6//! - [`OpenConnectReply`]
7//! - [`SessionInfoRequest`]
8//! - [`SessionInfoReply`]
9//! - [`IncompatibleProtocolVersion`]
10//!
11//! During this stage, the client and server are exchanging information about each other, such as
12//! the server id, the client id, the mtu size, etc, to prepare for the connection handshake.
13use std::net::SocketAddr;
14
15use super::RakPacket;
16#[cfg(feature = "mcpe")]
17pub use crate::protocol::mcpe::UnconnectedPong;
18use crate::protocol::Magic;
19use crate::protocol::RAKNET_HEADER_FRAME_OVERHEAD;
20use crate::register_packets;
21
22use binary_util::interfaces::{Reader, Writer};
23use binary_util::io::{ByteReader, ByteWriter};
24use binary_util::BinaryIo;
25
26/// This is an enum of all offline packets.
27///
28/// You can use this to read and write offline packets,
29/// with the `binary_util` traits `Reader` and `Writer`.
30#[derive(Clone, Debug, BinaryIo)]
31#[repr(u8)]
32pub enum OfflinePacket {
33    UnconnectedPing(UnconnectedPing) = 0x01,
34    UnconnectedPong(UnconnectedPong) = 0x1c,
35    OpenConnectRequest(OpenConnectRequest) = 0x05,
36    OpenConnectReply(OpenConnectReply) = 0x06,
37    SessionInfoRequest(SessionInfoRequest) = 0x07,
38    SessionInfoReply(SessionInfoReply) = 0x08,
39    IncompatibleProtocolVersion(IncompatibleProtocolVersion) = 0x19,
40}
41
42register_packets! {
43    Offline is OfflinePacket,
44    UnconnectedPing,
45    UnconnectedPong,
46    OpenConnectRequest,
47    OpenConnectReply,
48    SessionInfoRequest,
49    SessionInfoReply,
50    IncompatibleProtocolVersion
51}
52
53/// Send to the other peer expecting a [`UnconnectedPong`] packet,
54/// this is used to determine the latency between the client and the server,
55/// and to determine if the server is online.
56///
57/// If the peer does not respond with a [`UnconnectedPong`] packet, the iniatior should
58/// expect that the server is offline.
59#[derive(Debug, Clone, BinaryIo)]
60pub struct UnconnectedPing {
61    pub timestamp: u64,
62    pub magic: Magic,
63    pub client_id: i64,
64}
65
66/// Sent in response to a [`UnconnectedPing`] packet.
67/// This is used to determine the latency between the client and the server, and to determine
68/// that the peer is online.
69///
70/// <style>
71/// .warning-2 {
72///     background: rgba(255,240,76,0.34) !important;
73///     padding: 0.75em;
74///     border-left: 2px solid #fce811;
75///     font-family: "Source Serif 4", NanumBarunGothic, serif;
76///  }
77///
78/// .warning-2 code {
79///     background: rgba(211,201,88,0.64) !important;
80/// }
81///
82/// .notice-2 {
83///     background: rgba(88, 211, 255, 0.34) !important;
84///     padding: 0.75em;
85///     border-left: 2px solid #4c96ff;
86///     font-family: "Source Serif 4", NanumBarunGothic, serif;
87/// }
88///
89/// .notice-2 code {
90///     background: rgba(88, 211, 255, 0.64) !important;
91/// }
92/// </style>
93/// <div class="notice-2">
94///     <strong> Note: </strong>
95///    <p>
96///         If the client is a Minecraft: Bedrock Edition client, this packet is not sent
97///         and the
98///         <a
99///             href="/rak-rs/latest/protocol/mcpe/struct.UnconnectedPong.html"
100///             title="struct rak_rs::protocol::mcpe::UnconnectedPing">
101///             UnconnectedPong
102///         </a>
103///         from the <code>mcpe</code> module is sent instead.
104///   </p>
105/// </div>
106///
107/// [`UnconnectedPong`]: crate::protocol::packet::offline::UnconnectedPong
108#[cfg(not(feature = "mcpe"))]
109#[derive(Debug, Clone, BinaryIo)]
110pub struct UnconnectedPong {
111    pub timestamp: u64,
112    pub server_id: u64,
113    pub magic: Magic,
114}
115
116/// This packet is the equivelant of the `OpenConnectRequest` packet in RakNet.
117///
118/// This packet is sent by the peer to a server to request a connection.
119/// It contains information about the client, such as the protocol version, and the mtu size.
120/// The peer should expect a [`OpenConnectReply`] packet in response to this packet, if the
121/// server accepts the connection. Otherwise, the peer should expect a [`IncompatibleProtocolVersion`]
122/// packet to be sent to indicate that the server does not support the protocol version.
123///
124/// <style>
125/// .warning-2 {
126///     background: rgba(255,240,76,0.34) !important;
127///     padding: 0.75em;
128///     border-left: 2px solid #fce811;
129///     font-family: "Source Serif 4", NanumBarunGothic, serif;
130///  }
131///
132/// .warning-2 code {
133///     background: rgba(211,201,88,0.64) !important;
134/// }
135///
136/// .notice-2 {
137///     background: rgba(88, 211, 255, 0.34) !important;
138///     padding: 0.75em;
139///     border-left: 2px solid #4c96ff;
140///     font-family: "Source Serif 4", NanumBarunGothic, serif;
141/// }
142///
143/// .notice-2 code {
144///     background: rgba(88, 211, 255, 0.64) !important;
145/// }
146/// </style>
147/// <div class="notice-2">
148///     <strong> Note: </strong>
149///    <p>
150///         Internally this packet is padded by the given
151///         <code>mtu_size</code> in the packet. This is done by appending null bytes
152///         to the current buffer of the packet which is calculated by adding the difference
153///         between the <code>mtu_size</code> and the current length.
154///   </p>
155/// </div>
156#[derive(Debug, Clone)]
157pub struct OpenConnectRequest {
158    pub protocol: u8,  // 9
159    pub mtu_size: u16, // 500
160}
161
162impl Reader<OpenConnectRequest> for OpenConnectRequest {
163    fn read(buf: &mut ByteReader) -> Result<OpenConnectRequest, std::io::Error> {
164        let len = buf.as_slice().len();
165        buf.read_type::<Magic>()?;
166        Ok(OpenConnectRequest {
167            protocol: buf.read_u8()?,
168            mtu_size: (len + RAKNET_HEADER_FRAME_OVERHEAD as usize) as u16,
169        })
170    }
171}
172
173impl Writer for OpenConnectRequest {
174    fn write(&self, buf: &mut ByteWriter) -> Result<(), std::io::Error> {
175        buf.write_type::<Magic>(&Magic::new())?;
176        buf.write_u8(self.protocol)?;
177        // padding
178        // remove 28 bytes from the mtu size
179        let mtu_size = self.mtu_size - RAKNET_HEADER_FRAME_OVERHEAD as u16;
180        for _ in 0..mtu_size {
181            buf.write_u8(0)?;
182        }
183        Ok(())
184    }
185}
186
187// Open Connection Reply
188/// This packet is sent in response to a [`OpenConnectRequest`] packet, and confirms
189/// the information sent by the peer in the [`OpenConnectRequest`] packet.
190///
191/// This packet is the equivalent of the `Open Connect Reply 1` within the original RakNet implementation.
192///
193/// If the server chooses to deny the connection, it should send a [`IncompatibleProtocolVersion`]
194/// or ignore the packet.
195#[derive(Debug, Clone, BinaryIo)]
196pub struct OpenConnectReply {
197    pub magic: Magic,
198    pub server_id: u64,
199    pub security: bool,
200    pub mtu_size: u16,
201}
202
203/// This packet is sent after receiving a [`OpenConnectReply`] packet, and confirms
204/// that the peer wishes to proceed with the connection. The information within this packet
205/// is primarily used to get the external address of the peer.
206///
207/// This packet is the equivalent of the `Open Connect Request 2` within the original RakNet implementation.
208#[derive(Debug, Clone, BinaryIo)]
209pub struct SessionInfoRequest {
210    pub magic: Magic,
211    /// The socket address of the peer you are sending
212    /// this packet to.
213    pub address: SocketAddr,
214    /// The mtu size of the peer you are sending this packet to.
215    pub mtu_size: u16,
216    /// Your internal client id.
217    pub client_id: i64,
218}
219
220/// This packet is sent in response to a [`SessionInfoRequest`] packet, and confirms
221/// all the information sent by the peer in the [`SessionInfoRequest`] packet. This packet
222/// also specifies the external address of the peer, as well as whether or not
223/// encryption at the RakNet level is enabled on the server.
224///
225/// This packet is the equivalent of the `Open Connect Reply 2` within the original RakNet implementation.
226#[derive(Debug, Clone, BinaryIo)]
227pub struct SessionInfoReply {
228    pub magic: Magic,
229    pub server_id: u64,
230    pub client_address: SocketAddr,
231    pub mtu_size: u16,
232    pub security: bool,
233}
234
235/// This packet is sent by the server to indicate that the server does not support the
236/// protocol version of the client.
237#[derive(Debug, Clone, BinaryIo)]
238pub struct IncompatibleProtocolVersion {
239    pub protocol: u8,
240    pub magic: Magic,
241    pub server_id: u64,
242}