mirror of
https://github.com/netbirdio/IronRDP.git
synced 2026-05-22 18:43:12 -07:00
feat(server)!: add server_codecs_capabilities()
Teach the server to support customizable codecs set. Use the same logic/parsing as the client codecs configuration. Replace "with_remote_fx" with "codecs". Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
This commit is contained in:
committed by
Benoît Cortier
parent
727c9b7710
commit
d3aaa43c23
@@ -32,9 +32,9 @@ pub use self::bitmap_cache::{
|
||||
BitmapCache, BitmapCacheRev2, CacheEntry, CacheFlags, CellInfo, BITMAP_CACHE_ENTRIES_NUM,
|
||||
};
|
||||
pub use self::bitmap_codecs::{
|
||||
client_codecs_capabilities, BitmapCodecs, CaptureFlags, Codec, CodecId, CodecProperty, EntropyBits, Guid, NsCodec,
|
||||
RemoteFxContainer, RfxCaps, RfxCapset, RfxClientCapsContainer, RfxICap, RfxICapFlags, CODEC_ID_NONE,
|
||||
CODEC_ID_REMOTEFX,
|
||||
client_codecs_capabilities, server_codecs_capabilities, BitmapCodecs, CaptureFlags, Codec, CodecId, CodecProperty,
|
||||
EntropyBits, Guid, NsCodec, RemoteFxContainer, RfxCaps, RfxCapset, RfxClientCapsContainer, RfxICap, RfxICapFlags,
|
||||
CODEC_ID_NONE, CODEC_ID_REMOTEFX,
|
||||
};
|
||||
pub use self::brush::{Brush, SupportLevel};
|
||||
pub use self::frame_acknowledge::FrameAcknowledge;
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
mod tests;
|
||||
|
||||
use core::fmt::{self, Debug};
|
||||
use std::collections::HashMap;
|
||||
|
||||
use bitflags::bitflags;
|
||||
use ironrdp_core::{
|
||||
@@ -641,6 +642,30 @@ impl CodecId {
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_codecs_config<'a>(codecs: &'a [&'a str]) -> Result<HashMap<&'a str, bool>, String> {
|
||||
let mut result = HashMap::new();
|
||||
|
||||
for &codec_str in codecs {
|
||||
if let Some(colon_index) = codec_str.find(':') {
|
||||
let codec_name = &codec_str[0..colon_index];
|
||||
let state_str = &codec_str[colon_index + 1..];
|
||||
|
||||
let state = match state_str {
|
||||
"on" => true,
|
||||
"off" => false,
|
||||
_ => return Err(format!("Unhandled configuration: {state_str}")),
|
||||
};
|
||||
|
||||
result.insert(codec_name, state);
|
||||
} else {
|
||||
// No colon found, assume it's "on"
|
||||
result.insert(codec_str, true);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
/// This function generates a list of client codec capabilities based on the
|
||||
/// provided configuration.
|
||||
///
|
||||
@@ -659,32 +684,6 @@ impl CodecId {
|
||||
/// A vector of `Codec` structs representing the codec capabilities, or an error
|
||||
/// suitable for CLI.
|
||||
pub fn client_codecs_capabilities(config: &[&str]) -> Result<BitmapCodecs, String> {
|
||||
use std::collections::HashMap;
|
||||
|
||||
fn parse_codecs_config<'a>(codecs: &'a [&'a str]) -> Result<HashMap<&'a str, bool>, String> {
|
||||
let mut result = HashMap::new();
|
||||
|
||||
for &codec_str in codecs {
|
||||
if let Some(colon_index) = codec_str.find(':') {
|
||||
let codec_name = &codec_str[0..colon_index];
|
||||
let state_str = &codec_str[colon_index + 1..];
|
||||
|
||||
let state = match state_str {
|
||||
"on" => true,
|
||||
"off" => false,
|
||||
_ => return Err(format!("Unhandled configuration: {state_str}")),
|
||||
};
|
||||
|
||||
result.insert(codec_name, state);
|
||||
} else {
|
||||
// No colon found, assume it's "on"
|
||||
result.insert(codec_str, true);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
if config.contains(&"help") {
|
||||
return Err(r#"
|
||||
List of codecs:
|
||||
@@ -692,6 +691,7 @@ List of codecs:
|
||||
"#
|
||||
.to_owned());
|
||||
}
|
||||
|
||||
let mut config = parse_codecs_config(config)?;
|
||||
let mut codecs = vec![];
|
||||
|
||||
@@ -715,3 +715,51 @@ List of codecs:
|
||||
|
||||
Ok(BitmapCodecs(codecs))
|
||||
}
|
||||
|
||||
/// This function generates a list of server codec capabilities based on the
|
||||
/// provided configuration.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `config` - A slice of string slices that specifies which codecs to include
|
||||
/// in the capabilities. Codecs can be explicitly turned on ("codec:on") or
|
||||
/// off ("codec:off").
|
||||
///
|
||||
/// # List of codecs
|
||||
///
|
||||
/// * `remotefx` (on by default)
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// A vector of `Codec` structs representing the codec capabilities, or an help message suitable
|
||||
/// for CLI errors.
|
||||
pub fn server_codecs_capabilities(config: &[&str]) -> Result<BitmapCodecs, String> {
|
||||
if config.contains(&"help") {
|
||||
return Err(r#"
|
||||
List of codecs:
|
||||
- `remotefx` (on by default)
|
||||
"#
|
||||
.to_owned());
|
||||
}
|
||||
|
||||
let mut config = parse_codecs_config(config)?;
|
||||
let mut codecs = vec![];
|
||||
|
||||
if config.remove("remotefx").unwrap_or(true) {
|
||||
codecs.push(Codec {
|
||||
id: 0,
|
||||
property: CodecProperty::RemoteFx(RemoteFxContainer::ServerContainer(1)),
|
||||
});
|
||||
codecs.push(Codec {
|
||||
id: 0,
|
||||
property: CodecProperty::ImageRemoteFx(RemoteFxContainer::ServerContainer(1)),
|
||||
});
|
||||
}
|
||||
|
||||
let codec_names = config.keys().copied().collect::<Vec<_>>().join(", ");
|
||||
if !codec_names.is_empty() {
|
||||
return Err(format!("Unknown codecs: {codec_names}"));
|
||||
}
|
||||
|
||||
Ok(BitmapCodecs(codecs))
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
use core::net::SocketAddr;
|
||||
|
||||
use anyhow::Result;
|
||||
use ironrdp_pdu::rdp::capability_sets::{server_codecs_capabilities, BitmapCodecs};
|
||||
use tokio_rustls::TlsAcceptor;
|
||||
|
||||
use super::clipboard::CliprdrServerFactory;
|
||||
@@ -25,7 +26,7 @@ pub struct WantsDisplay {
|
||||
pub struct BuilderDone {
|
||||
addr: SocketAddr,
|
||||
security: RdpServerSecurity,
|
||||
with_remote_fx: bool,
|
||||
codecs: BitmapCodecs,
|
||||
handler: Box<dyn RdpServerInputHandler>,
|
||||
display: Box<dyn RdpServerDisplay>,
|
||||
cliprdr_factory: Option<Box<dyn CliprdrServerFactory>>,
|
||||
@@ -124,7 +125,7 @@ impl RdpServerBuilder<WantsDisplay> {
|
||||
display: Box::new(display),
|
||||
sound_factory: None,
|
||||
cliprdr_factory: None,
|
||||
with_remote_fx: true,
|
||||
codecs: server_codecs_capabilities(&[]).unwrap(),
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -138,7 +139,7 @@ impl RdpServerBuilder<WantsDisplay> {
|
||||
display: Box::new(NoopDisplay),
|
||||
sound_factory: None,
|
||||
cliprdr_factory: None,
|
||||
with_remote_fx: true,
|
||||
codecs: server_codecs_capabilities(&[]).unwrap(),
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -155,8 +156,8 @@ impl RdpServerBuilder<BuilderDone> {
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_remote_fx(mut self, enabled: bool) -> Self {
|
||||
self.state.with_remote_fx = enabled;
|
||||
pub fn with_bitmap_codecs(mut self, codecs: BitmapCodecs) -> Self {
|
||||
self.state.codecs = codecs;
|
||||
self
|
||||
}
|
||||
|
||||
@@ -165,7 +166,7 @@ impl RdpServerBuilder<BuilderDone> {
|
||||
RdpServerOptions {
|
||||
addr: self.state.addr,
|
||||
security: self.state.security,
|
||||
with_remote_fx: self.state.with_remote_fx,
|
||||
codecs: self.state.codecs,
|
||||
},
|
||||
self.state.handler,
|
||||
self.state.display,
|
||||
|
||||
@@ -12,7 +12,7 @@ pub(crate) fn capabilities(opts: &RdpServerOptions, size: DesktopSize) -> Vec<ca
|
||||
capability_sets::CapabilitySet::Input(input_capabilities()),
|
||||
capability_sets::CapabilitySet::VirtualChannel(virtual_channel_capabilities()),
|
||||
capability_sets::CapabilitySet::MultiFragmentUpdate(multifragment_update()),
|
||||
capability_sets::CapabilitySet::BitmapCodecs(bitmap_codecs(opts.with_remote_fx)),
|
||||
capability_sets::CapabilitySet::BitmapCodecs(opts.codecs.clone()),
|
||||
]
|
||||
}
|
||||
|
||||
@@ -87,20 +87,3 @@ fn multifragment_update() -> capability_sets::MultifragmentUpdate {
|
||||
max_request_size: 16_777_215,
|
||||
}
|
||||
}
|
||||
|
||||
fn bitmap_codecs(with_remote_fx: bool) -> capability_sets::BitmapCodecs {
|
||||
let mut codecs = Vec::new();
|
||||
if with_remote_fx {
|
||||
codecs.push(capability_sets::Codec {
|
||||
id: 0,
|
||||
property: capability_sets::CodecProperty::RemoteFx(capability_sets::RemoteFxContainer::ServerContainer(1)),
|
||||
});
|
||||
codecs.push(capability_sets::Codec {
|
||||
id: 0,
|
||||
property: capability_sets::CodecProperty::ImageRemoteFx(
|
||||
capability_sets::RemoteFxContainer::ServerContainer(1),
|
||||
),
|
||||
});
|
||||
}
|
||||
capability_sets::BitmapCodecs(codecs)
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ use ironrdp_displaycontrol::server::{DisplayControlHandler, DisplayControlServer
|
||||
use ironrdp_pdu::input::fast_path::{FastPathInput, FastPathInputEvent};
|
||||
use ironrdp_pdu::input::InputEventPdu;
|
||||
use ironrdp_pdu::mcs::{SendDataIndication, SendDataRequest};
|
||||
use ironrdp_pdu::rdp::capability_sets::{BitmapCodecs, CapabilitySet, CmdFlags, GeneralExtraFlags};
|
||||
use ironrdp_pdu::rdp::capability_sets::{BitmapCodecs, CapabilitySet, CmdFlags, CodecProperty, GeneralExtraFlags};
|
||||
pub use ironrdp_pdu::rdp::client_info::Credentials;
|
||||
use ironrdp_pdu::rdp::headers::{ServerDeactivateAll, ShareControlPdu};
|
||||
use ironrdp_pdu::x224::X224;
|
||||
@@ -38,7 +38,23 @@ use crate::{builder, capabilities, SoundServerFactory};
|
||||
pub struct RdpServerOptions {
|
||||
pub addr: SocketAddr,
|
||||
pub security: RdpServerSecurity,
|
||||
pub with_remote_fx: bool,
|
||||
pub codecs: BitmapCodecs,
|
||||
}
|
||||
|
||||
impl RdpServerOptions {
|
||||
fn has_image_remote_fx(&self) -> bool {
|
||||
self.codecs
|
||||
.0
|
||||
.iter()
|
||||
.any(|codec| matches!(codec.property, CodecProperty::ImageRemoteFx(_)))
|
||||
}
|
||||
|
||||
fn has_remote_fx(&self) -> bool {
|
||||
self.codecs
|
||||
.0
|
||||
.iter()
|
||||
.any(|codec| matches!(codec.property, CodecProperty::RemoteFx(_)))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
@@ -711,21 +727,21 @@ impl RdpServer {
|
||||
// We should distinguish parameters for both modes,
|
||||
// and somehow choose the "best", instead of picking
|
||||
// the last parsed here.
|
||||
rdp::capability_sets::CodecProperty::RemoteFx(
|
||||
rdp::capability_sets::RemoteFxContainer::ClientContainer(c),
|
||||
) if self.opts.with_remote_fx => {
|
||||
CodecProperty::RemoteFx(rdp::capability_sets::RemoteFxContainer::ClientContainer(c))
|
||||
if self.opts.has_remote_fx() =>
|
||||
{
|
||||
for caps in c.caps_data.0 .0 {
|
||||
update_codecs.set_remotefx(Some((caps.entropy_bits, codec.id)));
|
||||
}
|
||||
}
|
||||
rdp::capability_sets::CodecProperty::ImageRemoteFx(
|
||||
rdp::capability_sets::RemoteFxContainer::ClientContainer(c),
|
||||
) if self.opts.with_remote_fx => {
|
||||
CodecProperty::ImageRemoteFx(rdp::capability_sets::RemoteFxContainer::ClientContainer(
|
||||
c,
|
||||
)) if self.opts.has_image_remote_fx() => {
|
||||
for caps in c.caps_data.0 .0 {
|
||||
update_codecs.set_remotefx(Some((caps.entropy_bits, codec.id)));
|
||||
}
|
||||
}
|
||||
rdp::capability_sets::CodecProperty::NsCodec(_) => (),
|
||||
CodecProperty::NsCodec(_) => (),
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user