SilkroadFrame

Enum SilkroadFrame 

Source
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.

Fields

§count: u8
§crc: u8
§opcode: u16
§data: Bytes
§

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).

Fields

§content_size: usize
§encrypted_data: Bytes
§

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).

Fields

§count: u8
§crc: u8
§contained_opcode: u16
§contained_count: u16
§

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.

Fields

§count: u8
§crc: u8
§inner: Bytes

Implementations§

Source§

impl SilkroadFrame

Source

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.

Source

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.

Source

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)
Source

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.

Source

pub fn opcode(&self) -> Option<u16>

Tries to fetch the opcode of the frame, unless the packet is encrypted, which returns None.

Source

pub fn serialize(&self) -> Bytes

Tries to serialize this frame into a byte stream. It will allocate a buffer that matches the packet size into which it will serialize itself.

Trait Implementations§

Source§

impl Debug for SilkroadFrame

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Encoder<SilkroadFrame> for SilkroadCodec

Source§

type Error = Error

The type of encoding errors. Read more
Source§

fn encode( &mut self, item: SilkroadFrame, dst: &mut BytesMut, ) -> Result<(), Self::Error>

Encodes a frame into the buffer provided. Read more
Source§

impl PartialEq for SilkroadFrame

Source§

fn eq(&self, other: &SilkroadFrame) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0 · Source§

fn ne(&self, other: &Rhs) -> bool

Tests for !=. The default implementation is almost always sufficient, and should not be overridden without very good reason.
Source§

impl Eq for SilkroadFrame

Source§

impl StructuralPartialEq for SilkroadFrame

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.