Skip to content
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

Server resize follow-up #532

Merged
merged 11 commits into from
Aug 19, 2024
Merged

Server resize follow-up #532

merged 11 commits into from
Aug 19, 2024

Conversation

elmarco
Copy link
Contributor

@elmarco elmarco commented Aug 14, 2024

I forgot to squash BitmapEncoder support in #530.

The main part is handling pending incoming client message during deact-react; queuing and replaying them after acceptation.

@elmarco elmarco changed the title Resize Server resize follow-up Aug 14, 2024
@elmarco elmarco force-pushed the resize branch 2 times, most recently from 00ad7f6 to 12a6c98 Compare August 14, 2024 16:29
@CBenoit
Copy link
Member

CBenoit commented Aug 16, 2024

@elmarco Thank you!
Is it ready for review?

@elmarco
Copy link
Contributor Author

elmarco commented Aug 17, 2024

@elmarco Thank you! Is it ready for review?

yes, thanks

Copy link
Member

@CBenoit CBenoit left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are two commits with the same summary: feat(async): teach single_sequence_step() to keep unmatched PDUs

Did you intend to change the scope?

Copy link
Member

@CBenoit CBenoit left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Refactor code into something like this:

diff --git a/crates/ironrdp-async/src/framed.rs b/crates/ironrdp-async/src/framed.rs
index 2597f644..fa4cf600 100644
--- a/crates/ironrdp-async/src/framed.rs
+++ b/crates/ironrdp-async/src/framed.rs
@@ -60,10 +60,6 @@ impl<S> Framed<S> {
     pub fn peek(&self) -> &[u8] {
         &self.buf
     }
-
-    pub fn leftover_mut(&mut self) -> &mut BytesMut {
-        &mut self.buf
-    }
 }

 impl<S> Framed<S>
diff --git a/crates/ironrdp-server/src/server.rs b/crates/ironrdp-server/src/server.rs
index 63888d3d..e15deacb 100644
--- a/crates/ironrdp-server/src/server.rs
+++ b/crates/ironrdp-server/src/server.rs
@@ -17,6 +17,7 @@ use ironrdp_pdu::{self, decode, encode_vec, mcs, nego, rdp, Action, PduResult};
 use ironrdp_svc::{impl_as_any, server_encode_svc_messages, StaticChannelId, StaticChannelSet, SvcProcessor};
 use ironrdp_tokio::{Framed, FramedRead, FramedWrite, TokioFramed};
 use rdpsnd::server::{RdpsndServer, RdpsndServerMessage};
+use tokio::io::{AsyncRead, AsyncWrite};
 use tokio::net::{TcpListener, TcpStream};
 use tokio::sync::{mpsc, Mutex};
 use tokio::task;
@@ -797,25 +798,29 @@ impl RdpServer {
         }
     }

-    async fn accept_finalize<S>(&mut self, mut framed: Framed<S>, mut acceptor: Acceptor) -> Result<()>
+    async fn accept_finalize<S>(&mut self, mut framed: TokioFramed<S>, mut acceptor: Acceptor) -> Result<()>
     where
-        S: FramedRead + FramedWrite,
+        S: AsyncRead + AsyncWrite + Sync + Send + Unpin,
     {
         let mut other_pdus = None;
+
         loop {
             let (new_framed, result) = ironrdp_acceptor::accept_finalize(framed, &mut acceptor, other_pdus.as_mut())
                 .await
                 .context("failed to accept client during finalize")?;

-            framed = new_framed;
+            let (stream, mut leftover) = new_framed.into_inner();

             debug!(other_pdus = other_pdus.as_ref().map_or(0, |o| o.len()));
             if let Some(pdus) = other_pdus.take() {
-                let mut leftover: Vec<_> = pdus.iter().flat_map(|p| p.iter().copied()).collect();
-                leftover.extend_from_slice(&framed.leftover_mut().split()[..]);
-                framed.leftover_mut().extend_from_slice(&leftover);
+                let unmatched_frames = pdus.into_iter().flatten();
+                let previous_leftover = leftover.split();
+                leftover.extend(unmatched_frames);
+                leftover.extend_from_slice(&previous_leftover);
             }

+            framed = TokioFramed::new_with_leftover(stream, leftover);
+
             match self.client_accepted(&mut framed, result).await? {
                 RunState::Continue => {
                     unreachable!();

crates/ironrdp-async/src/framed.rs Outdated Show resolved Hide resolved
crates/ironrdp-async/src/framed.rs Outdated Show resolved Hide resolved
crates/ironrdp-server/src/server.rs Outdated Show resolved Hide resolved
Signed-off-by: Marc-André Lureau <[email protected]>
 #[wasm_bindgen] creates annoying warnings, such as:

 rust-analyzer: Function `__wasm_bindgen_generated_Session_apply_inputs` should have snake_case name, e.g. `__wasm_bindgen_generated_session_apply_inputs`

Signed-off-by: Marc-André Lureau <[email protected]>
This is not supported yet, and I am not sure how to do it atm.

Generally, server uses multiple of 4 widths, and client has surface
capabilities, so this path is unlikely.

Signed-off-by: Marc-André Lureau <[email protected]>
…hint

When compiled in debug mode, the code checks the expected Action hint.
But in release mode, no checks are done and the it will have to fail
later.

Instead, return whether the PDU is matching the hint, so the caller can
decide what to do in this case.

Signed-off-by: Marc-André Lureau <[email protected]>
@CBenoit
Copy link
Member

CBenoit commented Aug 19, 2024

@elmarco By the way, are you getting these client messages from mstsc as well? I’m wondering if the real fix should not be about modifying the IronRDP client to not send messages unrelated to the connection sequence before the connection sequence is over.

@elmarco
Copy link
Contributor Author

elmarco commented Aug 19, 2024

@elmarco By the way, are you getting these client messages from mstsc as well? I’m wondering if the real fix should not be about modifying the IronRDP client to not send messages unrelated to the connection sequence before the connection sequence is over.

Yes. The reactivation sequence is triggered by the server, so there can always be client messages in flight.

@CBenoit
Copy link
Member

CBenoit commented Aug 19, 2024

@elmarco By the way, are you getting these client messages from mstsc as well? I’m wondering if the real fix should not be about modifying the IronRDP client to not send messages unrelated to the connection sequence before the connection sequence is over.

Yes. The reactivation sequence is triggered by the server, so there can always be client messages in flight.

Oh right. It becomes a problem during the reactivation sequence. Sounds good.

…ytes

The caller can then decide what to do.

Signed-off-by: Marc-André Lureau <[email protected]>
…d bytes

The caller can then decide what to do.

Signed-off-by: Marc-André Lureau <[email protected]>
The caller can gather the unmatching/unexpected PDUs as necessary.

Signed-off-by: Marc-André Lureau <[email protected]>
The caller can gather the unmatching/unexpected PDUs as necessary.

Signed-off-by: Marc-André Lureau <[email protected]>
The client may have pending messages while the activation-reactivation
sequence is ongoing. Let's collect them in this case and restore them
after successfull reconnection.

Signed-off-by: Marc-André Lureau <[email protected]>
Copy link
Member

@CBenoit CBenoit left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

@CBenoit CBenoit enabled auto-merge (rebase) August 19, 2024 10:43
@CBenoit CBenoit merged commit 09ae0d0 into Devolutions:master Aug 19, 2024
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

2 participants