Skip to content

Commit

Permalink
Fixed ConnectAsync to abort when the cancellation token is cancelled
Browse files Browse the repository at this point in the history
Fixes issue #798
  • Loading branch information
jstedfast committed Dec 29, 2018
1 parent 3c04a66 commit 1baf768
Showing 1 changed file with 5 additions and 17 deletions.
22 changes: 5 additions & 17 deletions MailKit/Net/SocketUtils.cs
Original file line number Diff line number Diff line change
Expand Up @@ -70,22 +70,6 @@ public void Throw ()
}
}

static IAsyncResult BeginConnectAsync (AsyncCallback callback, object state)
{
var connect = (AsyncConnectState) state;

return connect.Socket.BeginConnect (connect.Host, connect.Port, callback, state);
}

static void EndConnectAsync (IAsyncResult ar)
{
var connect = (AsyncConnectState) ar.AsyncState;

connect.CancellationToken.ThrowIfCancellationRequested ();
connect.Socket.EndConnect (ar);
connect.IsConnected = true;
}

// Note: EndConnect needs to catch all exceptions
static void EndConnect (IAsyncResult ar)
{
Expand Down Expand Up @@ -127,7 +111,11 @@ public static async Task<Socket> ConnectAsync (string host, int port, IPEndPoint
var state = new AsyncConnectState (socket, host, port, cancellationToken);

if (doAsync) {
await Task.Factory.FromAsync (BeginConnectAsync, EndConnectAsync, state).ConfigureAwait (false);
await Task.Run (() => {
var ar = socket.BeginConnect (host, port, EndConnect, state);
Wait (ar, cancellationToken);
state.Throw ();
}, cancellationToken).ConfigureAwait (false);
} else {
var ar = socket.BeginConnect (host, port, EndConnect, state);
Wait (ar, cancellationToken);
Expand Down

2 comments on commit 1baf768

@SirRufo
Copy link

Choose a reason for hiding this comment

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

This should work, but maybe you want to have some more elegant code for this like

static async Task<Socket> ConnectSocketAsync(string host, int port, CancellationToken cancellationToken = default)
{
    var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
    var tcs = new TaskCompletionSource<bool>();
    cancellationToken.Register(() => tcs.SetCanceled(), false);
    var ar = socket.BeginConnect(host, port, e => tcs.SetResult(true), null);
    try
    {
        await tcs.Task;
        socket.EndConnect(ar);
        return socket;
    }
    catch (Exception)
    {
        socket.Close();
        throw;
    }

}

@jstedfast
Copy link
Owner Author

Choose a reason for hiding this comment

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

Yea, this is a bit simpler. Thanks.

Please sign in to comment.