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}