Skip to main content

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 something like a 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 carry a larger logical payload. A massive header is sent first, containing the number of following container frames as well as the logical packet’s opcode, and is then followed by the specified number of containers, which contain the data. The container count does not describe how many application objects can be deserialized from that data. 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 byte-stream, 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()
.expect("the frame is representable");
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 following SilkroadFrame::MassiveContainer frame(s). contained_count is the number of following container frames, not a count of application objects.

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 and contributes data to the logical payload identified by that header.

Fields

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

Implementations§

Source§

impl SilkroadFrame

Source

pub fn parse(data: &[u8]) -> Result<(usize, SilkroadFrame), FrameParseError>

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 returns FrameParseError::Incomplete. The returned value in FrameParseError::Incomplete is not guaranteed to be the exact necessary bytes; it is possible to get it multiple times, even when ensuring at least the amount of returned requested bytes were added. This is because if we need the header info first and only then can we know the expected size. Complete but malformed frames return a structural parsing error.

Source

pub fn from_data(data: &[u8]) -> Result<SilkroadFrame, FrameParseError>

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.

The data must contain the two-byte opcode, one-byte security count, one-byte CRC, and any frame-specific fields. Malformed data is returned as a typed error.

Source

pub fn content_size(&self) -> Result<FrameContentSize, FrameEncodeError>

Computes the value represented by the 15-bit length header field. Depending on the type of frame, this is either:

  • The application payload size (basic frame)
  • The unpadded application payload size, excluding the encrypted opcode, count, and CRC fields (encrypted frame)
  • A fixed size (massive header frame)
  • The mode byte and payload size (massive container frame)
Source

pub fn validate(&self) -> Result<(), FrameEncodeError>

Validates that this frame has a representable length and coherent shape.

Source

pub fn packet_size(&self) -> Result<usize, FrameEncodeError>

Computes the total encoded size of this frame.

This includes the length header and, for encrypted frames, the fixed encrypted fields and block padding.

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) -> Result<Bytes, FrameEncodeError>

Tries to serialize this frame into a byte stream.

Frames whose content length cannot be represented by the protocol’s 15-bit length field are rejected before any output is produced.

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 Eq for SilkroadFrame

Source§

impl PartialEq for SilkroadFrame

Source§

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

Equality operator ==. Read more
1.0.0 (const: unstable) · Source§

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

Inequality operator !=. Read more
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 = !

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

fn try_from(value: U) -> Result<T, !>

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.