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

refactor(rust): second iteration of now-proto-pdu library #7

Merged
merged 6 commits into from
Jan 14, 2025

Conversation

pacmancoder
Copy link
Contributor

@pacmancoder pacmancoder commented Dec 24, 2024

  • Updated protocol encode/decode logic according to the last NOW-PROTO specification
  • Removed internal types suck as VarStr/VarBuf from public API
  • Simplified Rust API
  • Added more docs
  • Fixed a lot of crate API issues from initial implementation
  • Reduced allocations.
    • Decoded PDUs are borrowed by default. Ownership is only required for Error types.
    • It is possible to avoid allocations completely during PDU construction when <'static> values for strings/buffers are used.
  • Improved tests

@pacmancoder pacmancoder force-pushed the feat/now-proto-improvements branch from 9fb68f0 to 767d128 Compare December 24, 2024 01:04
@pacmancoder pacmancoder force-pushed the feat/now-proto-improvements branch from 767d128 to 805c4b5 Compare December 24, 2024 01:11
@pacmancoder pacmancoder changed the title Feat/now proto improvements refactoring(rust): second iteration of NOW-proto library Dec 24, 2024
@@ -973,17 +1014,13 @@ The NOW_EXEC_DATA_MSG message is used to send input/output data as part of a rem

| Flag | Meaning |
|----------------------------------------|---------------------------------|
| NOW_EXEC_FLAG_DATA_FIRST<br>0x00000001 | This is the first data message. |
Copy link
Contributor Author

@pacmancoder pacmancoder Dec 24, 2024

Choose a reason for hiding this comment

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

protocol change: first flag for streams is not necessary and only complicates data API/protocol

@pacmancoder pacmancoder requested a review from CBenoit December 24, 2024 11:26
@pacmancoder pacmancoder marked this pull request as ready for review December 24, 2024 11:59
@pacmancoder pacmancoder self-assigned this Dec 24, 2024
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.

Great job! Looks good to me, but I left a few high-level comments about documentation and protocol specification changes.

Here is another suggestion I have: rename the folder doc to docs. It’s typically called docs everywhere, so it’s best to stick to this convention. (Devolutions Gateway and rust-analyzer to cite those two)

Comment on lines +14 to +19
1. Update the protocol specification in `doc/NOW-spec.md`.
1. Bump the protocol version number.
1. Update the Rust implementation of the protocol in `crates/now-proto-pdu`.
1. Bump current protocol version in `NowProtoVersion::CURRENT`
1. Update the C# protocol implementation (WIP)
1. Update C# clients (WIP)
Copy link
Member

Choose a reason for hiding this comment

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

question/suggestion: Is using 1. everywhere intended?

Suggested change
1. Update the protocol specification in `doc/NOW-spec.md`.
1. Bump the protocol version number.
1. Update the Rust implementation of the protocol in `crates/now-proto-pdu`.
1. Bump current protocol version in `NowProtoVersion::CURRENT`
1. Update the C# protocol implementation (WIP)
1. Update C# clients (WIP)
1. Update the protocol specification in `doc/NOW-spec.md`.
- Bump the protocol version number.
2. Update the Rust implementation of the protocol in `crates/now-proto-pdu`.
- Bump current protocol version in `NowProtoVersion::CURRENT`
3. Update the C# protocol implementation (WIP)
4. Update C# clients (WIP)

Copy link
Contributor Author

@pacmancoder pacmancoder Jan 9, 2025

Choose a reason for hiding this comment

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

Yes, this was intended -- It is allowed by markdown and correctly displayed in rendered form as a numbered list -- subsequent structural changes in this list will not require changing all numbers manually when adding or removing steps and will produce smaller diff in PR. However, if you have a strong opinion on that, I could change this 🙂

Copy link
Member

Choose a reason for hiding this comment

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

Oh, I didn't know! I think it's fine! 🙂
It's a bit less nice to read in source, but I can see how it's useful when adding new elements in between. Maybe we don't need the sublists to be numbered though. I would just suggest to use bullets there if you don't mind, but up to you!

Comment on lines 24 to 25
ironrdp-core = { version = "0.1.2", features = ["alloc"] }
ironrdp-error = { version = "0.1.1", features = ["alloc"] }
Copy link
Member

Choose a reason for hiding this comment

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

suggestion: As a rule of thumb, do not specify the patch number as you may be over-constraining the dependency graph. It’s fine for pre-1.x crates, but typically you’re better off never specifying them.

Comment on lines +6 to +25
## Library architecture details
- The library only provides encoding/decoding functions for the NOW-proto protocol, transport layer
and session processing logic should be implemented by the client/server.
- `#[no_std]` compatible. Requires `alloc`.
- PDUs could contain borrowed data by default to avoid unnecessary string/vec allocations when
parsing. The only exception is error types which are `'static` and may allocate if optional
message is set.
- PDUs are immutable by default. PDU constructors take only required fields, optional fields are
set using implicit builder pattern (consuming `.with_*` and `.set_*` methods).
- User-facing `bitfield` types should be avoied in the public API if incorrect usage could lead to
invalid PDUs. E.g. `ExecData`'s stdio stream flags are represented as a bitfield, but exactly
one of the flags should be set at a time. The public API should provide a safe way to set and
retrieve these flags. Channel capabilities flags on the other hand could all be set independently,
therefore it is safe to expose them in the public API.
- Primitive protocol types e.g `NOW_STRING` should not be exposed in the public API.
- Message validition should be always checked in the PDU constructor(s). If the message have
variable fields, it should be ensured that it could fit into the message body (`u32`).
- PDUs should NOT fail on deserialization if message body have more data to ensure backwards
compatibility with future protocol versions (e.g. new fields added to the end of the message in
the new protocol version).
Copy link
Member

Choose a reason for hiding this comment

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

praise: This kind of architecture overview is nice! 👍

Comment on lines +30 to +34
## Versioning
Crate version is not tied to the protocol version (e.g. Introduction of breaking changes in the
crate API does not necessarily mean a protocol version bump and vice versa). The currently
implemented protocol version is stored in [`NowProtoVersion::CURRENT`] and should be updated
accordingly when the protocol is updated.
Copy link
Member

Choose a reason for hiding this comment

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

suggestion: Maybe a good idea to mention that a handshake/negotiation packet is used to accommodate older servers and vice-versa, meaning that even a major bump in the protocol version does not mean we need a major bump for the crate, as the older protocol version is still supported.

doc/NOW-spec.md Outdated

- `NOW_STATUS_ERROR_KIND_WINAPI`: code contains standard WinAPI error.
- `NOW_STATUS_ERROR_KIND_UNIX`: code contains standard UNIX error code.

**errorMessage(variable, optional)**: this value contains either optional error message if
**errorMessage(variable)**: this value contains either optional error message if
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
**errorMessage(variable)**: this value contains either optional error message if
**errorMessage(variable)**: this value contains either an error message if

doc/NOW-spec.md Outdated

- `NOW_STATUS_ERROR_KIND_WINAPI`: code contains standard WinAPI error.
- `NOW_STATUS_ERROR_KIND_UNIX`: code contains standard UNIX error code.

**errorMessage(variable, optional)**: this value contains either optional error message if
**errorMessage(variable)**: this value contains either optional error message if
`NOW_STATUS_ERROR_MESSAGE` flag is set, or empty sting if the flag is not set.
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
`NOW_STATUS_ERROR_MESSAGE` flag is set, or empty sting if the flag is not set.
`NOW_STATUS_ERROR_MESSAGE` flag is set, or empty string if the flag is not set.

doc/NOW-spec.md Outdated
Comment on lines 804 to 805
The NOW_EXEC_ABORT_MSG message is used to abort a remote execution immediately. See NOW_EXEC_CANCEL_REQ if
the graceful session cancellation is needed instead. This message can be sent by the client at any point of session lifetime. The session is considered aborted as soon as this message is sent.
Copy link
Member

Choose a reason for hiding this comment

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

suggestion: I recommend you to use the "sentence-per-line" style: https://github.com/Devolutions/IronRDP/blob/25bbb2682c95419fc18a61cab81e29a0ab9f23d4/STYLE.md#sentence-per-line-style

Suggested change
The NOW_EXEC_ABORT_MSG message is used to abort a remote execution immediately. See NOW_EXEC_CANCEL_REQ if
the graceful session cancellation is needed instead. This message can be sent by the client at any point of session lifetime. The session is considered aborted as soon as this message is sent.
The NOW_EXEC_ABORT_MSG message is used to abort a remote execution immediately.
See NOW_EXEC_CANCEL_REQ if the graceful session cancellation is needed instead.
This message can be sent by the client at any point of session lifetime.
The session is considered aborted as soon as this message is sent.

@@ -743,7 +784,6 @@ The NOW_EXEC_MSG message is used to execute remote commands or scripts.

| Value | Meaning |
|-------|---------|
| NOW_EXEC_CAPSET_MSG_ID<br>0x00 | NOW_EXEC_CAPSET_MSG |
Copy link
Member

Choose a reason for hiding this comment

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

question: Are we removing this message? Is it superseded by something else?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yep. This was previosuly in exec message class -- now it was moved to channel message class

doc/NOW-spec.md Outdated
@@ -385,6 +387,45 @@ the specified interval, it should consider the connection as lost.

**msgFlags (2 bytes)**: The message flags.

#### NOW_CHANNEL_TERMINATE_MSG
Copy link
Member

Choose a reason for hiding this comment

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

naming: What about this naming?

Suggested change
#### NOW_CHANNEL_TERMINATE_MSG
#### NOW_CHANNEL_CLOSE_MSG

doc/NOW-spec.md Outdated
@@ -761,7 +801,8 @@ The NOW_EXEC_MSG message is used to execute remote commands or scripts.

#### NOW_EXEC_ABORT_MSG

The NOW_EXEC_ABORT_MSG message is used to abort a remote execution immediately due to an unrecoverable error. This message can be sent at any time without an explicit response message. The session is considered aborted as soon as this message is sent.
The NOW_EXEC_ABORT_MSG message is used to abort a remote execution immediately. See NOW_EXEC_CANCEL_REQ if
Copy link
Member

Choose a reason for hiding this comment

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

praise: +1 for referencing other relevant messages.

@CBenoit CBenoit changed the title refactoring(rust): second iteration of NOW-proto library refactor(rust): second iteration of now-proto-pdu library Jan 8, 2025
@CBenoit
Copy link
Member

CBenoit commented Jan 8, 2025

Another remark: the commit type for refactoring is refactor. I’m also unsure if we want to go with a "rust" scope, but I’ll let you decide what’s best here. (Not specifying a scope at all purposefully may make sense too.)

@pacmancoder pacmancoder merged commit 050fb03 into master Jan 14, 2025
9 checks passed
@pacmancoder pacmancoder deleted the feat/now-proto-improvements branch January 14, 2025 11:01
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