Skip to content

feat(ffi): expose API for RDCleanPath #855

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 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 crates/ironrdp/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ dvc = ["dep:ironrdp-dvc"]
rdpdr = ["dep:ironrdp-rdpdr"]
rdpsnd = ["dep:ironrdp-rdpsnd"]
displaycontrol = ["dep:ironrdp-displaycontrol"]
rdcleanpath = ["dep:ironrdp-rdcleanpath"]
# Internal (PRIVATE!) features used to aid testing.
# Don't rely on these whatsoever. They may disappear at any time.
__bench = ["ironrdp-server/__bench"]
Expand All @@ -50,6 +51,7 @@ ironrdp-dvc = { path = "../ironrdp-dvc", version = "0.3", optional = true } # pu
ironrdp-rdpdr = { path = "../ironrdp-rdpdr", version = "0.3", optional = true } # public
ironrdp-rdpsnd = { path = "../ironrdp-rdpsnd", version = "0.5", optional = true } # public
ironrdp-displaycontrol = { path = "../ironrdp-displaycontrol", version = "0.3", optional = true } # public
ironrdp-rdcleanpath = { path = "../ironrdp-rdcleanpath", version = "0.1", optional = true } # public

[dev-dependencies]
ironrdp-blocking = { path = "../ironrdp-blocking", version = "0.5.0" }
Expand Down
4 changes: 4 additions & 0 deletions crates/ironrdp/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,3 +63,7 @@ pub use ironrdp_session as session;
#[cfg(feature = "svc")]
#[doc(inline)]
pub use ironrdp_svc as svc;

#[cfg(feature = "rdcleanpath")]
#[doc(inline)]
pub use ironrdp_rdcleanpath as rdclean_path;
2 changes: 1 addition & 1 deletion ffi/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ doctest = false
[dependencies]
diplomat = "0.7"
diplomat-runtime = "0.7"
ironrdp = { path = "../crates/ironrdp", features = ["session", "connector", "dvc", "svc", "rdpdr", "rdpsnd", "graphics", "input", "cliprdr", "displaycontrol"] }
ironrdp = { path = "../crates/ironrdp", features = ["session", "connector", "dvc", "svc", "rdpdr", "rdpsnd", "graphics", "input", "cliprdr", "displaycontrol","rdcleanpath"] }
ironrdp-cliprdr-native.path = "../crates/ironrdp-cliprdr-native"
ironrdp-core = { path = "../crates/ironrdp-core", features = ["alloc"] }
sspi = { version = "0.15", features = ["network_client"] }
Expand Down
61 changes: 48 additions & 13 deletions ffi/dotnet/Devolutions.IronRdp.AvaloniaExample/MainWindow.axaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
using System;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Net.Security;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
Expand All @@ -22,7 +23,7 @@ public partial class MainWindow : Window
readonly InputDatabase? _inputDatabase = InputDatabase.New();
ActiveStage? _activeStage;
DecodedImage? _decodedImage;
Framed<SslStream>? _framed;
Framed<Stream>? _framed;
WinCliprdr? _cliprdr;
private readonly RendererModel _renderModel;
private Image? _imageControl;
Expand Down Expand Up @@ -79,8 +80,10 @@ private void OnOpened(object? sender, EventArgs e)
var password = Environment.GetEnvironmentVariable("IRONRDP_PASSWORD");
var domain = Environment.GetEnvironmentVariable("IRONRDP_DOMAIN");
var server = Environment.GetEnvironmentVariable("IRONRDP_SERVER");
var wsProxy = Environment.GetEnvironmentVariable("IRONRDP_PROXY");
var wsProxyToken = Environment.GetEnvironmentVariable("IRONRDP_PROXY_TOKEN");

if (username == null || password == null || domain == null || server == null)
if (username == null || password == null || server == null)
{
var errorMessage =
"Please set the IRONRDP_USERNAME, IRONRDP_PASSWORD, IRONRDP_DOMAIN, and RONRDP_SERVER environment variables";
Expand All @@ -106,15 +109,41 @@ private void OnOpened(object? sender, EventArgs e)
BeforeConnectSetup();
Task.Run(async () =>
{
var (res, framed) = await Connection.Connect(config, server, factory);
this._decodedImage = DecodedImage.New(PixelFormat.RgbA32, res.GetDesktopSize().GetWidth(),
res.GetDesktopSize().GetHeight());
this._activeStage = ActiveStage.New(res);
this._framed = framed;
ReadPduAndProcessActiveStage();
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
try
{

ConnectionResult res;
Framed<Stream> framed;
//wsProxy = null;
if (wsProxy != null && wsProxyToken != null)
{
Debug.WriteLine("Connecting via WebSocket proxy");
(res, framed) = await Connection.ConnectWs(
config,
new RdCleanPathConfig(new Uri(wsProxy), wsProxyToken),
server,
factory);
}
else
{
Debug.WriteLine("Connecting directly to server");
(res, framed) = await Connection.Connect(config, server, factory);
}
Debug.WriteLine("Connection success");
this._decodedImage = DecodedImage.New(PixelFormat.RgbA32, res.GetDesktopSize().GetWidth(),
res.GetDesktopSize().GetHeight());
this._activeStage = ActiveStage.New(res);
this._framed = framed;
ReadPduAndProcessActiveStage();
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
HandleClipboardEvents();
}
}
catch (Exception e)
{
HandleClipboardEvents();
Debug.WriteLine(e);
this.Close();
}
});
}
Expand Down Expand Up @@ -260,12 +289,17 @@ private void HandleClipboardEvents()
});
}

private static Config BuildConfig(string username, string password, string domain, int width, int height)
private static Config BuildConfig(string username, string password, string? domain, int width, int height)
{
ConfigBuilder configBuilder = ConfigBuilder.New();

configBuilder.WithUsernameAndPassword(username, password);
configBuilder.SetDomain(domain);
if (domain != null)
{
configBuilder.SetDomain(domain);
}
configBuilder.SetEnableCredssp(true);
configBuilder.SetEnableTls(true);
configBuilder.SetDesktopSize((ushort)height, (ushort)width);
configBuilder.SetClientName("IronRdp");
configBuilder.SetClientDir("C:\\");
Expand Down Expand Up @@ -395,6 +429,7 @@ private async Task<bool> HandleActiveStageOutput(ActiveStageOutputIterator outpu
var output =
outputIterator
.Next()!; // outputIterator.Next() is not null since outputIterator.IsEmpty() is false
Debug.WriteLine($"Output type: {output.GetType()}, Output enum type : {output.GetEnumType()}");
if (output.GetEnumType() == ActiveStageOutputType.Terminate)
{
return false;
Expand All @@ -418,7 +453,7 @@ private async Task<bool> HandleActiveStageOutput(ActiveStageOutputIterator outpu
var writeBuf = WriteBuf.New();
while (true)
{
await Connection.SingleSequenceStep(activationSequence, writeBuf,_framed!);
await Connection.SingleSequenceStep(activationSequence, writeBuf, _framed!);

if (activationSequence.GetState().GetType() != ConnectionActivationStateType.Finalized)
continue;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,19 @@
<PackageReference Include="SixLabors.ImageSharp" Version="3.1.7" />
</ItemGroup>

<ItemGroup>
<Compile Update="Properties\Resources.Designer.cs">
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
<DependentUpon>Resources.resx</DependentUpon>
</Compile>
</ItemGroup>

<ItemGroup>
<EmbeddedResource Update="Properties\Resources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
</EmbeddedResource>
</ItemGroup>

</Project>
75 changes: 56 additions & 19 deletions ffi/dotnet/Devolutions.IronRdp.ConnectExample/Program.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using SixLabors.ImageSharp;
using System.Diagnostics;
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.PixelFormats;

namespace Devolutions.IronRdp.ConnectExample
Expand All @@ -19,11 +20,30 @@ static async Task Main(string[] args)
var serverName = arguments["--serverName"];
var username = arguments["--username"];
var password = arguments["--password"];
var domain = arguments["--domain"];
arguments.TryGetValue("--domain", out var domain);
arguments.TryGetValue("--proxy", out var wsProxy);
arguments.TryGetValue("--proxyToken", out var wsProxyToken);

try
{
var (res, framed) = await Connection.Connect(buildConfig(serverName, username, password, domain, 1980, 1080), serverName, null);
ConnectionResult res;
Framed<Stream> framed;
if (wsProxyToken != null && wsProxy != null)
{
(res, framed) = await Connection.ConnectWs(
buildConfig(serverName, username, password, domain, 1980, 1080),
new RdCleanPathConfig(new Uri(wsProxy), wsProxyToken),
serverName,
null);
}
else
{
(res, framed) = await Connection.Connect(
buildConfig(serverName, username, password, domain, 1980, 1080),
serverName,
null);
}

var decodedImage = DecodedImage.New(PixelFormat.RgbA32, res.GetDesktopSize().GetWidth(), res.GetDesktopSize().GetHeight());
var activeState = ActiveStage.New(res);
var keepLooping = true;
Expand All @@ -37,22 +57,22 @@ static async Task Main(string[] args)
var pduReadTask = await readPduTask;
action = pduReadTask.Item1;
payload = pduReadTask.Item2;
Console.WriteLine($"Action: {action}");
Debug.WriteLine($"Action: {action}");
}
else
{
Console.WriteLine("Timeout");
Debug.WriteLine("Timeout");
break;
}
var outputIterator = activeState.Process(decodedImage, action, payload);

while (!outputIterator.IsEmpty())
{
var output = outputIterator.Next()!; // outputIterator.Next() is not null since outputIterator.IsEmpty() is false
Console.WriteLine($"Output type: {output.GetType()}");
Debug.WriteLine($"Output type: {output.GetType()}, Output enum type : {output.GetEnumType()}");
if (output.GetEnumType() == ActiveStageOutputType.Terminate)
{
Console.WriteLine("Connection terminated.");
Debug.WriteLine("Connection terminated.");
keepLooping = false;
}

Expand All @@ -66,8 +86,7 @@ static async Task Main(string[] args)
}
}

saveImage(decodedImage, "output.png");

saveImage(decodedImage, "C:\\dev\\IronRDP\\output.bmp");
}
catch (Exception e)
{
Expand Down Expand Up @@ -104,7 +123,7 @@ private static void saveImage(DecodedImage decodedImage, string v)
}

// Save the image as bitmap.
image.Save("./output.bmp");
image.Save(v);
}

static Dictionary<string, string>? ParseArguments(string[] args)
Expand Down Expand Up @@ -134,6 +153,10 @@ private static void saveImage(DecodedImage decodedImage, string v)
return null;
}
lastKey = arg;
}
else if (arg == "\\" || arg == "//")
{

}
else
{
Expand All @@ -160,34 +183,48 @@ private static void saveImage(DecodedImage decodedImage, string v)

static bool IsValidArgument(string argument)
{
var validArguments = new List<string> { "--serverName", "--username", "--password", "--domain" };
var validArguments = new List<string>
{
"--serverName",
"--username",
"--password",
"--domain",
"--proxy",
"--proxyToken"
};
return validArguments.Contains(argument);
}

static void PrintHelp()
{
Console.WriteLine("Usage: dotnet run -- [OPTIONS]");
Console.WriteLine("Options:");
Console.WriteLine(" --serverName <serverName> The name of the server to connect to.");
Console.WriteLine(" --username <username> The username for connection.");
Console.WriteLine(" --password <password> The password for connection.");
Console.WriteLine(" --domain <domain> The domain of the server.");
Console.WriteLine(" --help Show this message and exit.");
Console.WriteLine(" --serverName <serverName> The name of the server to connect to.");
Console.WriteLine(" --username <username> The username for connection.");
Console.WriteLine(" --password <password> The password for connection.");
Console.WriteLine(" --domain <domain> The domain of the server.");
Console.WriteLine(" --proxy <url> WebSocket proxy URL.");
Console.WriteLine(" --proxyToken <token> Authentication token for the proxy.");
Console.WriteLine(" --help Show this message and exit.");
}

private static Config buildConfig(string servername, string username, string password, string domain, int width, int height)
private static Config buildConfig(string servername, string username, string password, string? domain, int width, int height)
{
ConfigBuilder configBuilder = ConfigBuilder.New();

configBuilder.WithUsernameAndPassword(username, password);
configBuilder.SetDomain(domain);
if (domain != null)
{
configBuilder.SetDomain(domain);
}
configBuilder.SetEnableCredssp(true);
configBuilder.SetEnableTls(true);
configBuilder.SetDesktopSize((ushort)height, (ushort)width);
configBuilder.SetClientName("IronRdp");
configBuilder.SetClientDir("C:\\");
configBuilder.SetPerformanceFlags(PerformanceFlags.NewDefault());

return configBuilder.Build();
}

}
}

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

Loading
Loading