Skip to content

Commit

Permalink
feat: initial server support (#167)
Browse files Browse the repository at this point in the history
  • Loading branch information
mihneabuz authored Aug 25, 2023
1 parent 1132126 commit 74e95f6
Show file tree
Hide file tree
Showing 32 changed files with 3,204 additions and 235 deletions.
28 changes: 28 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ expect-test = "1"
ironrdp-async = { version = "0.1", path = "crates/ironrdp-async" }
ironrdp-cliprdr = { version = "0.1", path = "crates/ironrdp-cliprdr" }
ironrdp-connector = { version = "0.1", path = "crates/ironrdp-connector" }
ironrdp-acceptor = { version = "0.1", path = "crates/ironrdp-acceptor" }
ironrdp-error = { version = "0.1", path = "crates/ironrdp-error" }
ironrdp-futures = { version = "0.1", path = "crates/ironrdp-futures" }
ironrdp-fuzzing = { path = "crates/ironrdp-fuzzing" }
Expand All @@ -38,6 +39,7 @@ ironrdp-session = { version = "0.1", path = "crates/ironrdp-session" }
ironrdp-testsuite-core = { path = "crates/ironrdp-testsuite-core" }
ironrdp-tls = { version = "0.1", path = "crates/ironrdp-tls" }
ironrdp-tokio = { version = "0.1", path = "crates/ironrdp-tokio" }
ironrdp-server = { version = "0.1", path = "crates/ironrdp-server" }
ironrdp = { version = "0.5", path = "crates/ironrdp" }
proptest = "1.1.0"
rstest = "0.17.0"
Expand Down
22 changes: 22 additions & 0 deletions crates/ironrdp-acceptor/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
[package]
name = "ironrdp-acceptor"
version = "0.1.0"
readme = "README.md"
description = ""
edition.workspace = true
license.workspace = true
homepage.workspace = true
repository.workspace = true
authors.workspace = true
keywords.workspace = true
categories.workspace = true

[lib]
doctest = false
test = false

[dependencies]
ironrdp-pdu.workspace = true
ironrdp-connector.workspace = true
ironrdp-async.workspace = true
tracing.workspace = true
3 changes: 3 additions & 0 deletions crates/ironrdp-acceptor/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# IronRDP Acceptor

State machine for the server connection acceptance sequence.
168 changes: 168 additions & 0 deletions crates/ironrdp-acceptor/src/channel_connection.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
use std::collections::HashSet;

use ironrdp_connector::{ConnectorError, ConnectorErrorExt, ConnectorResult, Sequence, State, Written};
use ironrdp_pdu as pdu;
use pdu::mcs;

#[derive(Debug)]
pub struct ChannelConnectionSequence {
state: ChannelConnectionState,
user_channel_id: u16,
channels: HashSet<u16>,
}

#[derive(Default, Debug)]
pub enum ChannelConnectionState {
#[default]
Consumed,

WaitErectDomainRequest,
WaitAttachUserRequest,
SendAttachUserConfirm,
WaitChannelJoinRequest {
joined: HashSet<u16>,
},
SendChannelJoinConfirm {
joined: HashSet<u16>,
channel_id: u16,
},
AllJoined,
}

impl State for ChannelConnectionState {
fn name(&self) -> &'static str {
match self {
Self::Consumed => "Consumed",
Self::WaitErectDomainRequest => "WaitErectDomainRequest",
Self::WaitAttachUserRequest => "WaitAttachUserRequest",
Self::SendAttachUserConfirm => "SendAttachUserConfirm",
Self::WaitChannelJoinRequest { .. } => "WaitChannelJoinRequest",
Self::SendChannelJoinConfirm { .. } => "SendChannelJoinConfirm",
Self::AllJoined { .. } => "AllJoined",
}
}

fn is_terminal(&self) -> bool {
matches!(self, Self::AllJoined { .. })
}

fn as_any(&self) -> &dyn core::any::Any {
self
}
}

impl Sequence for ChannelConnectionSequence {
fn next_pdu_hint(&self) -> Option<&dyn pdu::PduHint> {
match &self.state {
ChannelConnectionState::Consumed => None,
ChannelConnectionState::WaitErectDomainRequest => Some(&pdu::X224_HINT),
ChannelConnectionState::WaitAttachUserRequest => Some(&pdu::X224_HINT),
ChannelConnectionState::SendAttachUserConfirm => None,
ChannelConnectionState::WaitChannelJoinRequest { .. } => Some(&pdu::X224_HINT),
ChannelConnectionState::SendChannelJoinConfirm { .. } => None,
ChannelConnectionState::AllJoined { .. } => None,
}
}

fn state(&self) -> &dyn State {
&self.state
}

fn step(&mut self, input: &[u8], output: &mut Vec<u8>) -> ConnectorResult<Written> {
let (written, next_state) = match std::mem::take(&mut self.state) {
ChannelConnectionState::WaitErectDomainRequest => {
let erect_domain_request =
ironrdp_pdu::decode::<mcs::ErectDomainPdu>(input).map_err(ConnectorError::pdu)?;

debug!(message = ?erect_domain_request, "Received");

(Written::Nothing, ChannelConnectionState::WaitAttachUserRequest)
}

ChannelConnectionState::WaitAttachUserRequest => {
let attach_user_request =
ironrdp_pdu::decode::<mcs::AttachUserRequest>(input).map_err(ConnectorError::pdu)?;

debug!(message = ?attach_user_request, "Received");

(Written::Nothing, ChannelConnectionState::SendAttachUserConfirm)
}

ChannelConnectionState::SendAttachUserConfirm => {
let attach_user_confirm = mcs::AttachUserConfirm {
result: 0,
initiator_id: self.user_channel_id,
};

debug!(message = ?attach_user_confirm, "Send");

let written = ironrdp_pdu::encode_buf(&attach_user_confirm, output).map_err(ConnectorError::pdu)?;

(
Written::from_size(written)?,
ChannelConnectionState::WaitChannelJoinRequest { joined: HashSet::new() },
)
}

// TODO: support RNS_UD_CS_SUPPORT_SKIP_CHANNELJOIN
ChannelConnectionState::WaitChannelJoinRequest { joined } => {
let channel_request =
ironrdp_pdu::decode::<mcs::ChannelJoinRequest>(input).map_err(ConnectorError::pdu)?;

debug!(message = ?channel_request, "Received");

let channel_id = channel_request.channel_id;

(
Written::Nothing,
ChannelConnectionState::SendChannelJoinConfirm { joined, channel_id },
)
}

ChannelConnectionState::SendChannelJoinConfirm { mut joined, channel_id } => {
let channel_confirm = mcs::ChannelJoinConfirm {
result: 0,
initiator_id: self.user_channel_id,
requested_channel_id: channel_id,
channel_id,
};

debug!(message = ?channel_confirm, "Send");

let written = ironrdp_pdu::encode_buf(&channel_confirm, output).map_err(ConnectorError::pdu)?;

joined.insert(channel_id);

let state = if joined != self.channels {
ChannelConnectionState::WaitChannelJoinRequest { joined }
} else {
ChannelConnectionState::AllJoined {}
};

(Written::from_size(written)?, state)
}

_ => unreachable!(),
};

self.state = next_state;
Ok(written)
}
}

impl ChannelConnectionSequence {
pub fn new(user_channel_id: u16, io_channel_id: u16, other_channels: Vec<u16>) -> Self {
Self {
state: ChannelConnectionState::WaitErectDomainRequest,
user_channel_id,
channels: vec![user_channel_id, io_channel_id]
.into_iter()
.chain(other_channels.into_iter())
.collect(),
}
}

pub fn is_done(&self) -> bool {
self.state.is_terminal()
}
}
Loading

0 comments on commit 74e95f6

Please sign in to comment.