Example #1
0
            public sealed override Task ConnectAsync(EndPoint remoteAddress, EndPoint localAddress)
            {
                // todo: handle cancellation
                AbstractSocketChannel ch = this.Channel;

                if (!ch.Open)
                {
                    return(this.CreateClosedChannelExceptionTask());
                }

                try
                {
                    if (ch.connectPromise != null)
                    {
                        throw new InvalidOperationException("connection attempt already made");
                    }

                    bool wasActive = this.channel.Active;
                    if (ch.DoConnect(remoteAddress, localAddress))
                    {
                        this.FulfillConnectPromise(wasActive);
                        return(TaskEx.Completed);
                    }
                    else
                    {
                        ch.connectPromise = new TaskCompletionSource(remoteAddress);

                        // Schedule connect timeout.
                        TimeSpan connectTimeout = ch.Configuration.ConnectTimeout;
                        if (connectTimeout > TimeSpan.Zero)
                        {
                            ch.connectCancellationTask = ch.EventLoop.Schedule(
                                (c, a) =>
                            {
                                // todo: make static / cache delegate?..
                                var self = (AbstractSocketChannel)c;
                                // todo: call Socket.CancelConnectAsync(...)
                                TaskCompletionSource promise = self.connectPromise;
                                var cause = new ConnectTimeoutException("connection timed out: " + a.ToString());
                                if (promise != null && promise.TrySetException(cause))
                                {
                                    self.CloseAsync();
                                }
                            },
                                this.channel,
                                remoteAddress,
                                connectTimeout);
                        }

                        ch.connectPromise.Task.ContinueWith(
                            (t, s) =>
                        {
                            var c = (AbstractSocketChannel)s;
                            c.connectCancellationTask?.Cancel();
                            c.connectPromise = null;
                            c.CloseAsync();
                        },
                            ch,
                            TaskContinuationOptions.OnlyOnCanceled | TaskContinuationOptions.ExecuteSynchronously);

                        return(ch.connectPromise.Task);
                    }
                }
                catch (Exception ex)
                {
                    this.CloseIfClosed();
                    return(TaskEx.FromException(this.AnnotateConnectException(ex, remoteAddress)));
                }
            }