pub enum SilkroadFrame {
Packet {
count: u8,
crc: u8,
opcode: u16,
data: Bytes,
},
Encrypted {
content_size: usize,
encrypted_data: Bytes,
},
MassiveHeader {
count: u8,
crc: u8,
contained_opcode: u16,
contained_count: u16,
},
MassiveContainer {
count: u8,
crc: u8,
inner: Bytes,
},
}Expand description
A ‘frame’ denotes the most fundamental block of data that can be sent between the client and the server in Silkroad Online. Any and all operations or data exchanges are built on top of a kind of frame.
There are two categories of frames; normal frames and massive frames. A normal frame is the most common frame denoting a single operation using a specified opcode. This frame may be encrypted, causing everything but the length to require decrypting before being usable. Massive frames are used to bundle similar operations together. A massive header is sent first, containing the amount of operations as well as their opcode, and is then followed by the specified amount of containers, which now only contain the data. Thus, massive frames cannot be encrypted.
Every frame, including an encrypted frame, contains two additional bytes: a crc checksum and a cryptographically random count. The former is used to check for bitflips/modifications and the count to prevent replay attacks.
To read a frame from a bytestream, you can use the SilkroadFrame::parse function to try and parse a frame from those bytes:
let (_, frame) = SilkroadFrame::parse(&[0x00, 0x00, 0x01, 0x00, 0x00, 0x00]).unwrap();
assert_eq!(
frame,
SilkroadFrame::Packet {
count: 0,
crc: 0,
opcode: 1,
data: Bytes::new(),
}
);This works vice-versa, to write a frame into a byte stream, using SilkroadFrame::serialize:
let bytes = SilkroadFrame::Packet {
count: 0,
crc: 0,
opcode: 1,
data: Bytes::new()
}.serialize();
assert_eq!(bytes.as_ref(), &[0x00, 0x00, 0x01, 0x00, 0x00, 0x00]);Variants§
Packet
The most basic frame containing exactly one operation identified by its opcode.
Encrypted
A SilkroadFrame::Packet which is, however, still encrypted. This
contains the encrypted data and will first need to be decrypted (for
example, using the skrillax-security crate).
MassiveHeader
The header portion of a massive packet which contains information that is necessary for the identification and usage of the followed SilkroadFrame::MassiveContainer frame(s).
MassiveContainer
The data container portion of a massive packet. Must come after
a SilkroadFrame::MassiveHeader. Given the opcode and included
count specified in the header frame, contains the data for n
operations of the same opcode.
Implementations§
Source§impl SilkroadFrame
impl SilkroadFrame
Sourcepub fn parse(data: &[u8]) -> Result<(usize, SilkroadFrame), usize>
pub fn parse(data: &[u8]) -> Result<(usize, SilkroadFrame), usize>
Tries to parse the first possible frame from the given data slice. In addition to the created frame, it will also return the size of consumed bytes by the frame. If not enough data is available, it will return Err with the bytes required to finish the frame.
Sourcepub fn from_data(data: &[u8]) -> SilkroadFrame
pub fn from_data(data: &[u8]) -> SilkroadFrame
Creates a SilkroadFrame given the received data. Generally, this will result
in a SilkroadFrame::Packet, unless we encounter a packet with the opcode
0x600D, which is reserved for a massive packet, consisting of a
SilkroadFrame::MassiveHeader and multiple SilkroadFrame::MassiveContainers.
This assumes the data is well-formed, i.e. first two bytes opcode, one byte security count, one byte crc, and the rest data. If the data represents a massive frame, it’s also expected that the massive information has the correct format. In other cases, this will currently panic.
Sourcepub fn content_size(&self) -> usize
pub fn content_size(&self) -> usize
Computes the size that should be used for the length header field. Depending on the type of frame this is either:
- The size of the contained data (basic frame)
- Encrypted size without header, but possibly padding (encrypted frame)
- A fixed size (massive header frame)
- Container and data size (massive container frame)
Sourcepub fn packet_size(&self) -> usize
pub fn packet_size(&self) -> usize
Computes the total size of the network packet for this frame. This is different from Self::content_size as it includes the size of the header as well as the correct size for encrypted packets.