Skip to main content
Version: 0.8.0
Docs.rs: ironrdp-session

Overview

The ironrdp-session crate provides state machines for managing an active RDP session after the connection is established. It handles:
  • Fast-path and X.224 PDU processing
  • Graphics output (bitmaps, surface commands, RemoteFX)
  • Pointer (cursor) updates
  • Graceful disconnection
  • Bulk data decompression
Like ironrdp-connector, this crate is transport-agnostic and operates on byte buffers.

Core Types

ActiveStage

pub struct ActiveStage { /* ... */ }

impl ActiveStage {
    pub fn new(
        user_channel_id: u16,
        io_channel_id: u16,
        no_server_pointer: bool,
        pointer_software_rendering: bool,
        desktop_size: DesktopSize,
    ) -> Self;
    
    pub fn process(
        &mut self,
        image: &mut dyn image::DecodedImage,
        payload: &[u8],
        output_buf: &mut WriteBuf,
    ) -> SessionResult<ActiveStageOutput>;
}
Parameters:
user_channel_id
u16
MCS user channel ID from connection result
io_channel_id
u16
MCS I/O channel ID from connection result
no_server_pointer
bool
If true, render pointer locally instead of using server-provided cursor
pointer_software_rendering
bool
Use software rendering for pointer updates
desktop_size
DesktopSize
Initial desktop dimensions

ActiveStageOutput

pub enum ActiveStageOutput {
    GraphicsUpdate,
    PointerDefault,
    PointerHidden,
    PointerPosition { x: u16, y: u16 },
    PointerBitmap { /* ... */ },
    Terminate(GracefulDisconnectReason),
}
Output events from processing a PDU. Variants:
GraphicsUpdate
variant
Graphics data was decoded into the DecodedImage
PointerDefault
variant
Use the default system pointer
PointerHidden
variant
Hide the pointer
PointerPosition
variant
Move pointer to (x, y)
PointerBitmap
variant
Update pointer to a custom bitmap
Terminate
variant
Server requested graceful disconnection

GracefulDisconnectReason

pub enum GracefulDisconnectReason {
    UserInitiated,
    ServerInitiated,
    // ... other reasons
}

Image Handling

DecodedImage Trait

pub trait DecodedImage {
    fn width(&self) -> usize;
    fn height(&self) -> usize;
    
    fn from_bitmap(&mut self, region: &BitmapRegion<'_>) -> SessionResult<()>;
    fn read_to_buffer(&self, buffer: &mut [u8]) -> SessionResult<()>;
}
Implement this trait to receive decoded graphics updates. Example Implementation:
use ironrdp_session::image::{DecodedImage, BitmapRegion};
use ironrdp_session::SessionResult;

struct MyImage {
    width: usize,
    height: usize,
    data: Vec<u8>, // BGRA format
}

impl DecodedImage for MyImage {
    fn width(&self) -> usize { self.width }
    fn height(&self) -> usize { self.height }
    
    fn from_bitmap(&mut self, region: &BitmapRegion<'_>) -> SessionResult<()> {
        // Decode bitmap data into self.data at the specified region
        // region.left, region.top, region.width, region.height
        // region.pixel_format, region.pixel_data
        Ok(())
    }
    
    fn read_to_buffer(&self, buffer: &mut [u8]) -> SessionResult<()> {
        buffer.copy_from_slice(&self.data);
        Ok(())
    }
}

BitmapRegion

pub struct BitmapRegion<'a> {
    pub left: usize,
    pub top: usize,
    pub width: usize,
    pub height: usize,
    pub pixel_format: PixelFormat,
    pub pixel_data: &'a [u8],
}

PDU Processing Modules

Fast-Path

pub mod fast_path;
Processes fast-path output PDUs (most graphics updates).

X.224

pub mod x224;
Processes X.224-framed PDUs (licensing, capability sets).

Legacy

pub mod legacy;
Handles legacy graphics orders.

Pointer

pub mod pointer;
Pointer/cursor update processing.

RemoteFX

pub mod rfx;
RemoteFX tile decoding.

Usage Example

use ironrdp_session::{ActiveStage, ActiveStageOutput};
use ironrdp_connector::{ConnectionResult, DesktopSize};
use ironrdp_core::WriteBuf;

// After connection is established
let result: ConnectionResult = /* ... */;

let mut session = ActiveStage::new(
    result.user_channel_id,
    result.io_channel_id,
    result.no_server_pointer,
    result.pointer_software_rendering,
    result.desktop_size,
);

let mut image = MyImage::new(result.desktop_size.width, result.desktop_size.height);
let mut output = WriteBuf::new();

loop {
    // ... receive PDU data into input_buf
    
    match session.process(&mut image, &input_buf, &mut output)? {
        ActiveStageOutput::GraphicsUpdate => {
            // Image was updated, render it
            render_frame(&image);
        },
        ActiveStageOutput::PointerPosition { x, y } => {
            // Move cursor to (x, y)
        },
        ActiveStageOutput::Terminate(reason) => {
            println!("Session terminated: {:?}", reason);
            break;
        },
        _ => {}
    }
    
    // Send any output PDUs
    if !output.filled().is_empty() {
        // ... send output.filled() over network
        output.clear();
    }
}

Error Handling

pub type SessionResult<T> = Result<T, SessionError>;
pub type SessionError = ironrdp_error::Error<SessionErrorKind>;

#[non_exhaustive]
pub enum SessionErrorKind {
    Pdu(ironrdp_pdu::PduError),
    Encode(ironrdp_core::EncodeError),
    Decode(ironrdp_core::DecodeError),
    Reason(String),
    General,
    Custom,
}

Bulk Compression

The session automatically handles bulk decompression when the server sends compressed PDUs:
  • MPPC (8 KB or 64 KB history)
  • NCRUSH (RDP 6.0)
  • XCRUSH (RDP 6.1)
Compression is negotiated during connection via Config::compression_type in ironrdp-connector.

Features

qoi
feature
Enable QOI image codec support
qoiz
feature
Enable QOI + Zstd compressed image support (requires qoi)

Dependencies

  • ironrdp-core - Core traits (public)
  • ironrdp-pdu - PDU structures (public)
  • ironrdp-graphics - Image processing (public)
  • ironrdp-connector - Connection result types (public)
  • ironrdp-svc - Virtual channel support (public)
  • ironrdp-dvc - Dynamic virtual channels (public)
  • ironrdp-bulk - Bulk decompression
  • ironrdp-displaycontrol - Display control channel

Usage Notes

Image Ownership:
The DecodedImage is owned by the caller. The session decodes graphics updates directly into your image buffer, avoiding unnecessary copies.
PDU Framing:
The session expects complete PDUs (after TPKT/X.224/MCS unwrapping). Use ironrdp_pdu::find_size() to detect PDU boundaries in your framing layer.
Output Buffer:
Reuse the WriteBuf across calls:
let mut output = WriteBuf::new();
loop {
    session.process(&mut image, input, &mut output)?;
    // ... send output.filled()
    output.clear(); // Reuse buffer
}

See Also

Build docs developers (and LLMs) love