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

Windows Support for Sync implementation #172

Merged
merged 4 commits into from
Mar 27, 2023

Conversation

jsturtevant
Copy link
Collaborator

Fixes: #132

This PR adds initial support for Windows. The scope is fairly large, so it only adds support for sync implementation to keep it fairly reasonable 😬. It would be possible to split out some parts of the work into smaller PR's or commits as needed. I have two main commits but happy to make them more distinct. It also has all the changes from #171 so I can drop those once that merges 👍

Note: I am fairly new to Rust so might need some guidance on choices I made here. There is still some more work to be done (adding security file descriptors to named pipe for instance) in the PR but wanted to get it open for discussion on the general direction.

This PR does three main things:

  • moves unix specific calls out of the main server and client functions. It does this by introducing several new types: PipeListener, PipeConnection, and ClientConnection. These types contain the unix specific functionality to communicate with Unix Domain sockets and are hidden behind a conditional compilation flag for the OS target.
  • Adds the windows functionality for PipeListener, PipeConnection, and ClientConnection and does the few other changes required to build and run the example projects. This includes adding feature support to the examples so they wouldn't build the async projects (as the unix specific code hasn't been removed yet). Importantly I avoided changes to the code generation and service api, so there are minimal changes to the example code beyond changing the socket address to a namedpipe format.
  • Add windows build agents and modifies the example so it runs in an integration test using cargo test. This seemed like a good way to ensure the whole system (code generation, client build and sever/client) worked e2e for all the OSes.

Another thing to note is that this PR implements Windows support using named pipes. While windows does have a UDS implementation, Containerd does not currently support this. As one of the main uses for this is containerd so adding namedpipe support is needed.

@codecov
Copy link

codecov bot commented Feb 1, 2023

Codecov Report

Patch coverage has no change and project coverage change: -1.33 ⚠️

Comparison is base (34003e3) 25.76% compared to head (4975099) 24.43%.

Additional details and impacted files
@@            Coverage Diff             @@
##           master     #172      +/-   ##
==========================================
- Coverage   25.76%   24.43%   -1.33%     
==========================================
  Files          16       17       +1     
  Lines        2395     2525     +130     
==========================================
  Hits          617      617              
- Misses       1778     1908     +130     
Impacted Files Coverage Δ
src/asynchronous/client.rs 0.00% <0.00%> (ø)
src/asynchronous/stream.rs 0.00% <0.00%> (ø)
src/common.rs 35.57% <ø> (ø)
src/error.rs 55.55% <ø> (ø)
src/lib.rs 100.00% <ø> (ø)
src/sync/channel.rs 0.00% <0.00%> (ø)
src/sync/client.rs 0.00% <0.00%> (ø)
src/sync/server.rs 0.00% <0.00%> (ø)
src/sync/sys/unix/net.rs 0.00% <0.00%> (ø)
src/sync/utils.rs 0.00% <ø> (ø)

Help us with your feedback. Take ten seconds to tell us how you rate us. Have a feature suggestion? Share it here.

☔ View full report in Codecov by Sentry.
📢 Do you have feedback about the report comment? Let us know in this issue.

@cpuguy83 cpuguy83 requested review from mxpv and lifupan February 8, 2023 19:17
@dcantah dcantah self-requested a review February 8, 2023 19:25
Cargo.toml Outdated Show resolved Hide resolved
example/client.rs Outdated Show resolved Hide resolved
now.elapsed()
);
let show = match ac.online_cpu_mem(default_ctx(), &agent::OnlineCPUMemRequest::new()) {
Err(e) => format!("{:?}", e),
Ok(s) => format!("{:?}", s),
Err(Error::RpcStatus(s)) => {
Copy link
Member

Choose a reason for hiding this comment

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

assert! and assert_eq! can take additional parameters to act like format!

https://doc.rust-lang.org/std/macro.assert.html#custom-messages

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I tried this out but since the macro doesn't return anything it isn't working. It seems the formatting is only used when failed. From the doc: Expressions used as format arguments will only be evaluated if the assertion fails.

tests/sync-test.rs Outdated Show resolved Hide resolved
src/sync/sys/windows/net.rs Outdated Show resolved Hide resolved
src/sync/sys/windows/net.rs Outdated Show resolved Hide resolved
@Tim-Zhang
Copy link
Member

Wow, we have been looking forward for the feature for a long period of time, thank you very much for your PR @jsturtevant.
Since the PR is a bit large, I think the reviewers need some time to give suggestions. thank you again.

Makefile Show resolved Hide resolved
src/sync/utils.rs Outdated Show resolved Hide resolved
@@ -0,0 +1,303 @@
// Copyright (c) 2019 Ant Financial
Copy link

Choose a reason for hiding this comment

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

Seems need to update copyright?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

not sure what the policy is for this project?

Copy link
Collaborator

Choose a reason for hiding this comment

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

Is Copyright The containerd Authors. better?
And also for other new files.

Copy link
Member

Choose a reason for hiding this comment

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

Follow the old convention of this project you can licence all the new files with Copyright (c) 2021 [company name or your name], and @liubin 's suggestion is good either, I am open to it.

Copy link
Member

Choose a reason for hiding this comment

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

I think it'd make sense for @liubin's suggestion given this lives in the containerd org. The language shouldn't matter at all, but another data point for rust code is the rust-extensions repo follows the convention from the other projects and has the containerd authors copyrights for all of its crates.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I pulled the content for containerd/containerd (same as rust-extensions). Do all the mod.rs files need it too? Maybe we can follow up and change it all over with a CI check too?

@jsturtevant
Copy link
Collaborator Author

Since the PR is a bit large, I think the reviewers need some time to give suggestions. thank you again.

makes sense. If it helps I could break this into several PR's or commits. I put it mostly together since I think it helps to understand the bigger picture but if general direction makes sense we can split it into PR's like the following:

  • update examples to add asserts and run them as integration test
  • refactor Linux to move code to the conditional compilation
  • add windows implementation behind compilation

This might make it easier to track and comment on changes?

@jsturtevant
Copy link
Collaborator Author

I've also started to use these changes for add support for Windows to the shim code: containerd/rust-extensions#4 (comment). This will help me validate the some of the changes too.

@Tim-Zhang
Copy link
Member

Tim-Zhang commented Feb 13, 2023

Since the PR is a bit large, I think the reviewers need some time to give suggestions. thank you again.

makes sense. If it helps I could break this into several PR's or commits. I put it mostly together since I think it helps to understand the bigger picture but if general direction makes sense we can split it into PR's like the following:

  • update examples to add asserts and run them as integration test
  • refactor Linux to move code to the conditional compilation
  • add windows implementation behind compilation

This might make it easier to track and comment on changes?

After several reviewers have done their reviews, there is no need to split it I think.

src/sync/sys/windows/mod.rs Outdated Show resolved Hide resolved
@@ -0,0 +1,303 @@
// Copyright (c) 2019 Ant Financial
Copy link
Collaborator

Choose a reason for hiding this comment

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

Is Copyright The containerd Authors. better?
And also for other new files.

src/sync/client.rs Outdated Show resolved Hide resolved
src/sync/channel.rs Outdated Show resolved Hide resolved
src/sync/sys/unix/net.rs Outdated Show resolved Hide resolved
src/sync/server.rs Outdated Show resolved Hide resolved
src/sync/server.rs Outdated Show resolved Hide resolved
src/sync/server.rs Outdated Show resolved Hide resolved
Cargo.toml Outdated Show resolved Hide resolved
@@ -10,6 +10,10 @@ repository = "https://github.com/alipay/ttrpc-rust"
homepage = "https://github.com/alipay/ttrpc-rust"
description = "An example of ttrpc."

[dependencies]
Copy link
Member

Choose a reason for hiding this comment

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

I think cargo run --example async-server --features=async is not that easy to use, in my opinion, We can keep the example/Cargo.toml unchanged, import all features from ttrpc is ok because this is just an example

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

ok this makes sense, didn't think about it from that perspective. I did it this way since when you import async from ttrpc it fails to build due to async not working with Windows. I tried using conditional dependencies that brought in a feature based on OS but that didn't work due to rust-lang/cargo#1197 (note the nightly changes in cargo did work with rust-lang/cargo#7914 using rustup override set nightly & cargo +nightly build -Z features=itarget)

I was able to work around this by updating the async marcro to check for linux. Doing that also let me add the examples project to the workspace as well which is a nice improvement for the developer experience in VScode (gives intelisense and compile errors when editing it).

example/Cargo.toml Outdated Show resolved Hide resolved
example/protocols/mod.rs Outdated Show resolved Hide resolved
src/asynchronous/client.rs Outdated Show resolved Hide resolved
src/sync/sys/windows/net.rs Outdated Show resolved Hide resolved
src/sync/sys/windows/net.rs Outdated Show resolved Hide resolved
example/utils.rs Outdated Show resolved Hide resolved
example/utils.rs Outdated Show resolved Hide resolved
example/utils.rs Outdated Show resolved Hide resolved
@Tim-Zhang
Copy link
Member

@jsturtevant I have reviewed the code and left a few comments. I have also built a windows env and tested it and it works great.

@dcantah
Copy link
Member

dcantah commented Feb 14, 2023

@jsturtevant Going to block off some time on Friday to review this, thanks a ton! I'll set this up on my desktop to trial it out

@jsturtevant
Copy link
Collaborator Author

thanks for the reviews everyone! I've been testing this with the Rust Extensions and runwasi. Will be addressing feedback this week.

src/asynchronous/client.rs Outdated Show resolved Hide resolved
src/sync/channel.rs Outdated Show resolved Hide resolved
src/sync/channel.rs Outdated Show resolved Hide resolved
src/sync/client.rs Outdated Show resolved Hide resolved
src/sync/sys/windows/net.rs Outdated Show resolved Hide resolved
Comment on lines 133 to 151
let h = unsafe {
CreateNamedPipeW(
name.as_ptr(),
openmode,
PIPE_TYPE_BYTE,
PIPE_UNLIMITED_INSTANCES,
65536,
65536,
0,
std::ptr::null_mut(), // todo set this on first instance
)
};
Copy link
Member

Choose a reason for hiding this comment

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

We should add PIPE_REJECT_REMOTE_CLIENTS

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

added

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

@dcantah I was looking into the security descriptor. A null value sets the default security descriptor which only allows Admins and the current user (https://learn.microsoft.com/en-us/windows/win32/ipc/named-pipe-security-and-access-rights).

I was comparing to the way go-wino creates it, And I believe this is the same behavior although go-winio is using undocumented calls (ntCreateNamedPipeFile and rtlDefaultNpAcl) so has the additional calls to rtlDefaultNpAcl to set the default. In the case of the documented CreateNamedPipeW null provides a sane default of requiring admins.

src/sync/sys/windows/net.rs Outdated Show resolved Hide resolved
src/sync/sys/windows/net.rs Outdated Show resolved Hide resolved
@dcantah
Copy link
Member

dcantah commented Feb 22, 2023

@jsturtevant I'll try and do another pass soon, left some comments. Sorry for not getting to this on Friday 😐

@jsturtevant jsturtevant force-pushed the windows3 branch 3 times, most recently from 263aea0 to d5b76e3 Compare February 23, 2023 18:46
@jsturtevant
Copy link
Collaborator Author

@Tim-Zhang @dcantah @jiangliu @kzys This is ready for another round of reviews. I can squash all the commits but left them for now.

Copy link
Member

@Tim-Zhang Tim-Zhang left a comment

Choose a reason for hiding this comment

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

LGTM, thanks @jsturtevant

@jsturtevant
Copy link
Collaborator Author

I've rebased and added commit messages

Copy link
Member

@dcantah dcantah left a comment

Choose a reason for hiding this comment

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

Mostly bunch of formatting comments, but LGTM! I took this for a spin and it seemed to work fine. We can always iterate also

src/sync/client.rs Outdated Show resolved Hide resolved
src/sync/channel.rs Outdated Show resolved Hide resolved
src/sync/sys/windows/net.rs Outdated Show resolved Hide resolved
src/sync/sys/windows/net.rs Outdated Show resolved Hide resolved
src/sync/sys/windows/net.rs Outdated Show resolved Hide resolved
src/sync/sys/unix/net.rs Outdated Show resolved Hide resolved
Comment on lines +235 to +251
0 => {
return Err(Error::Windows(io::Error::last_os_error().raw_os_error().unwrap()))
}
_ => {
return Ok(bytes_transfered as usize)
}
Copy link
Member

Choose a reason for hiding this comment

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

Wonder if we should have a helper for this match pattern given how common it is

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Had the same thought and tried to move it to something like process_overlapped() but when I did things didn't work properly. Given it is only repeated twice (for read and write) I decided to keep it as is.

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 meant the general 0 or _ match pattern. accept, read, write, shutdown and close_handle follow this trend, but might not be worth the hassle. Probably clearer to have it in the call site

Copy link
Member

@dcantah dcantah left a comment

Choose a reason for hiding this comment

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

lgtm again

@jsturtevant
Copy link
Collaborator Author

I was testing with https://github.com/containerd/rust-extensions/tree/main/crates/shim and found the server.shutdown() would hang. I've pushed the fix on 3ac5b6e for review

@jsturtevant jsturtevant force-pushed the windows3 branch 2 times, most recently from aa6685a to 416d571 Compare March 7, 2023 16:47
@jsturtevant jsturtevant mentioned this pull request Mar 7, 2023
30 tasks
Copy link
Collaborator

@quanweiZhou quanweiZhou left a comment

Choose a reason for hiding this comment

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

Thanks, @jsturtevant few comments.

example/client.rs Outdated Show resolved Hide resolved
example/client.rs Outdated Show resolved Hide resolved
src/sync/sys/unix/net.rs Show resolved Hide resolved
src/sync/sys/unix/net.rs Show resolved Hide resolved
src/sync/utils.rs Show resolved Hide resolved
@Tim-Zhang
Copy link
Member

@jsturtevant Hi, It seems that there is a bug here:

error[E0308]: mismatched types
  --> src/sync/client.rs:56:9
   |
53 |     pub fn new(fd: RawFd) -> Client {
   |                              ------ expected `sync::client::Client` because of return type
...
56 |         Self::new_client(conn)
   |         ^^^^^^^^^^^^^^^^^^^^^^ expected struct `Client`, found enum `Result`
   |
   = note: expected struct `sync::client::Client`
                found enum `std::result::Result<sync::client::Client, error::Error>`

@jsturtevant
Copy link
Collaborator Author

@jsturtevant Hi, It seems that there is a bug here:

error[E0308]: mismatched types
  --> src/sync/client.rs:56:9
   |
53 |     pub fn new(fd: RawFd) -> Client {
   |                              ------ expected `sync::client::Client` because of return type
...
56 |         Self::new_client(conn)
   |         ^^^^^^^^^^^^^^^^^^^^^^ expected struct `Client`, found enum `Result`
   |
   = note: expected struct `sync::client::Client`
                found enum `std::result::Result<sync::client::Client, error::Error>`

I was missing the update on the linux file. I've fixed with the comment to resolve in the next update.

The pr is failing on clippy updates, I've opened #178 to resolve them and will rebase this once that is in.

Adds asserts to the example project so it will fail if something isn't work between the client and server.  This also adds an integration test that builds and runs the sync example so the changes to the project can be validated e2e.

Signed-off-by: James Sturtevant <[email protected]>
This moves unix specific calls out of the main server and client
functions.  It does this by introducing several new types: PipeListener, PipeConnection,  and ClientConnection.  These types are contain the unix specific functionality to communitcate with Unix Domain sockets and are hidden behind a conditional compilation flag.

Signed-off-by: James Sturtevant <[email protected]>
Adds the windows functionality for PipeListener, PipeConnection, and ClientConnection and does the few other changes required to build and run the example projects. This includes adding feature support to the examples so they wouldn't build the async projects (as the unix specific code hasn't been removed yet). Namedpipes are used as Containerd is one of the main use cases for this project on Windows and containerd only supports namedpipes.

Signed-off-by: James Sturtevant <[email protected]>
The connect namedpipe thread would be in a suspended state when shutdown on the server is called.  Setting the event to a signalled state to wake the thread up so everything can shut down properly.

Signed-off-by: James Sturtevant <[email protected]>
@jsturtevant
Copy link
Collaborator Author

I've rebased ontop of #179. Thanks for the help unblocking

@lifupan lifupan merged commit ebbb58e into containerd:master Mar 27, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Windows support
9 participants