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

Reintroduce Socket.DuplicateAndClose() on Windows #1760

Closed
antonfirsov opened this issue Jan 15, 2020 · 4 comments · Fixed by #1858
Closed

Reintroduce Socket.DuplicateAndClose() on Windows #1760

antonfirsov opened this issue Jan 15, 2020 · 4 comments · Fixed by #1858
Assignees
Milestone

Comments

@antonfirsov
Copy link
Member

antonfirsov commented Jan 15, 2020

In Framework we had DuplicateAndClose and a matching Socket(SocketInformation) constructor to allow transferring sockets to other Win32 processes.

.NET Core does not support this method because of the reasons described in the linked comments.

Upon the request of two internal partners we propose to reintroduce a constrained implementation with the following limitations/differences:

  • Socket duplication does not work with IOCP on OS level. In Framework it was possible to set socket.UseOnlyOverlappedIO = true to ensure that no completion ports are bound to the socket. This will be not supported in .NET Core, since the entire Windows implementation of async IO is based on IOCP.
  • The solution will be Windows-only, because the original design of SocketInformation API-s is strongly specific to that platform.

Proposal for preventing invalid usages

It's not possible to use asynchronous operations in both the original and the duplicate socket because of platform limitations in IOCP.

Framework behavior

await server.ReceiveAsync(receiveBuffer, SocketFlags.None);
SocketInformation info = server.DuplicateAndClose(procId);
Socket cloneServer = new Socket(info);

// throws mysterious, undocumented ArgumentException:
await cloneServer.ReceiveAsync(receiveBuffer, SocketFlags.None);

[EDIT] New propsal

await server.ReceiveAsync(receiveBuffer, SocketFlags.None);
SocketInformation info = server.DuplicateAndClose(procId);
Socket cloneServer = new Socket(info);

// Detect the corner case and throw InvalidOperationException
await cloneServer.ReceiveAsync(receiveBuffer, SocketFlags.None);

[EDIT] Original proposal

await server.ReceiveAsync(receiveBuffer, SocketFlags.None);

// throw InvalidOperationException in advance:
SocketInformation info = server.DuplicateAndClose(procId);

The downside of this design would be that we would prevent cloning a socket (previously used asynchronously) to be used for synchronous operations after being cloned. This is a very unlikely scenario though.

@Dotnet-GitSync-Bot Dotnet-GitSync-Bot added area-System.Net.Sockets untriaged New issue has not been triaged by the area owner labels Jan 15, 2020
@antonfirsov antonfirsov removed the untriaged New issue has not been triaged by the area owner label Jan 15, 2020
@antonfirsov antonfirsov self-assigned this Jan 15, 2020
@scalablecory
Copy link
Contributor

throw InvalidOperationException in advance

Are you able use existing state to do this? E.g. checking if the socket has a ThreadPoolBoundHandle.

The downside of this design would be that we would prevent cloning a socket (previously used asynchronously) to be used for synchronous operations after being cloned. This is a very unlikely scenario though.

I don't know how unlikely this is. If we wanted to enable this scenario, what would we need to do?

@antonfirsov
Copy link
Member Author

antonfirsov commented Jan 15, 2020

Are you able use existing state to do this? E.g. checking if the socket has a ThreadPoolBoundHandle.

Yes, SafeSocketHandle.IOCPBoundHandle is the ThreadPoolBoundHandle that is null until the very first asynchronous operation.

I don't know how unlikely this is. If we wanted to enable this scenario, what would we need to do?

The problem is logically similar to dotnet/corefx#42609. Instead of throwing in DuplicateAndClose, we either need to transfer an additional state flag in SocketInformation and explicitly watch it in async operations in the clone socket, or try to convert the internal ArgumentException to something more reasonable.

@scalablecory
Copy link
Contributor

The problem is logically similar to dotnet/corefx#42609.

It's similar in that you'd get fast-failure, but dissimilar in that using sync APIs on a socket that has been duplicated is a valid use.

try to convert the internal ArgumentException to something more reasonable.

Can we prototype what this would look like?

What I'm thinking is that users of DuplicateAndClose will probably have very specific scenarios that I'm not sure we can predict; disabling something that worked in the past might mean another issue down the road as more and more people migrate away from Framework. It's worth weighing the pros/cons of cleaning up the API vs keeping it compatible.

@antonfirsov
Copy link
Member Author

@scalablecory looks like it's possible to detect the specific case. I will throw InvalidOperationException when it's not possible to bind the socket to an IOCP. This will also help with #862 corner cases.

antonfirsov added a commit to antonfirsov/runtime that referenced this issue Jan 17, 2020
@karelz karelz added this to the 5.0 milestone Jan 22, 2020
antonfirsov added a commit that referenced this issue Feb 4, 2020
* reimplement socket duplication, fix #1760

* additional cleanup

* ungroup PNSE tests, no RemoteExecutor timeout

* address review findings

* fix path for Interop.WSADuplicateSocket.cs

* remove swallowing in Socket(SocketInformation)

* review suggestions

* make sure duplicate socket is not inheritable

* remove debug code leftover

* harden SocketPal.CreateSocket()

* blittable WSAPROTOCOL_INFOW

* additional naming fixes,

default System.Net.Sockets.sln configurations to Windows_NT again

* disposal on errors, improve comments, more tests

* nits

* handle GetSockName() error
@ghost ghost locked as resolved and limited conversation to collaborators Dec 11, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants