diff options
author | Martin Baulig <mabaul@microsoft.com> | 2019-08-01 13:31:25 +0300 |
---|---|---|
committer | Alexander Köplinger <alex.koeplinger@outlook.com> | 2019-08-01 13:31:25 +0300 |
commit | e92ecdc9ceb48d5b429e393b5cdeb5d75066fa1b (patch) | |
tree | 5a400504e6ea189591563bcf05108d564cefdeb0 /mcs/class/referencesource | |
parent | 0e6965f6bab67a33d081762615dae22cb7779d4b (diff) |
Fix `Socket.ConnectAsync(SocketAsyncEventArgs)` behavior. (#15947)
We need to clearly distinguish between synchronous and asynchronous completions
and avoid any ambiguities and race conditions when it comes to error handling.
On synchronous completion, we must not invoke the async completion delegate.
In `System.Net.Sockets/Socket.cs`, the internal `BeginSConnect()` and `BeginMConnect()`
now return a `bool` indicating whether or not an async operation is pending.
If any error happens prior to starting the async operation, then we shall call
`SocketAsyncResult.Complete(..., true)` and return `false`. And since this is
a synchronous completion, it's `AsyncCallback` will not be invoked.
In `referencesource/System/net/System/Net/Sockets/_MultipleConnectAsync.cs`,
I compared the entire file against the CoreFX version and then copied the
`AttemptConnection()` method from their implementation to adapt their behavior.
The difference is that on synchronous completion, the `InternalConnectCallback(null, args)`
should be invoked.
Diffstat (limited to 'mcs/class/referencesource')
-rw-r--r-- | mcs/class/referencesource/System/net/System/Net/Sockets/_MultipleConnectAsync.cs | 36 |
1 files changed, 28 insertions, 8 deletions
diff --git a/mcs/class/referencesource/System/net/System/Net/Sockets/_MultipleConnectAsync.cs b/mcs/class/referencesource/System/net/System/Net/Sockets/_MultipleConnectAsync.cs index b8a4275b4e2..3d623fac590 100644 --- a/mcs/class/referencesource/System/net/System/Net/Sockets/_MultipleConnectAsync.cs +++ b/mcs/class/referencesource/System/net/System/Net/Sockets/_MultipleConnectAsync.cs @@ -219,28 +219,48 @@ namespace System.Net.Sockets { try { - Socket attemptSocket = null; + Socket attemptSocket; IPAddress attemptAddress = GetNextAddress(out attemptSocket); if (attemptAddress == null) { - return new SocketException(SocketError.NoData); + return new SocketException((int)SocketError.NoData); } - GlobalLog.Assert(attemptSocket != null, "MultipleConnectAsync.AttemptConnection: attemptSocket is null!"); - internalArgs.RemoteEndPoint = new IPEndPoint(attemptAddress, endPoint.Port); - if (!attemptSocket.ConnectAsync(internalArgs)) + return AttemptConnection(attemptSocket, internalArgs); + } + catch (Exception e) + { + if (e is ObjectDisposedException) + { + NetEventSource.Fail(this, "unexpected ObjectDisposedException"); + } + return e; + } + } + + private Exception AttemptConnection(Socket attemptSocket, SocketAsyncEventArgs args) + { + try + { + if (attemptSocket == null) + { + NetEventSource.Fail(null, "attemptSocket is null!"); + } + + bool pending = attemptSocket.ConnectAsync(args); + if (!pending) { - return new SocketException(internalArgs.SocketError); + InternalConnectCallback(null, args); } } catch (ObjectDisposedException) { - // This can happen if the user closes the socket, and is equivalent to a call + // This can happen if the user closes the socket, and is equivalent to a call // to CancelConnectAsync - return new SocketException(SocketError.OperationAborted); + return new SocketException((int)SocketError.OperationAborted); } catch (Exception e) { |