Example #1
0
        private async Task HandleConnectionAsync(SshConnection connection, SshConnectionInfo connectionInfo)
        {
            try
            {
                try
                {
                    Task sendTask = SendLoopAsync(connection);
                    AddConnectionUser(sendTask);
                    AddConnectionUser(ReceiveLoopAsync(connection, connectionInfo));

                    // Wait for a task that runs as long as the connection.
                    await sendTask.ContinueWith(_ => { /* Ignore Failed/Canceled */ });
                }
                catch (Exception e) // Unexpected: the continuation doesn't throw.
                {
                    Abort(e);
                }
                finally
                {
                    Task[] connectionUsers;
                    lock (_gate)
                    {
                        connectionUsers = _connectionUsers !.ToArray();
                        // Accept no new users.
                        _connectionUsers = null;
                    }
                    // Wait for all connection users.
                    await Task.WhenAll(connectionUsers);
                }
            }
            catch (Exception e)
            {
                Abort(e); // Unlikely, Abort will be called already.
            }
            finally
            {
                connection.Dispose();
            }

            async void AddConnectionUser(Task task)
            {
                lock (_gate)
                {
                    _connectionUsers !.Add(task);
                }

                try
                {
                    await task;
                    RemoveConnectionUser(task);
                }
                catch (Exception e)
                {
                    RemoveConnectionUser(task);
                    Abort(e);
                }

                void RemoveConnectionUser(Task task)
                {
                    lock (_gate)
                    {
                        List <Task> connectionUsers = _connectionUsers !;

                        if (connectionUsers != null)
                        {
                            connectionUsers.Remove(task);
                        }
                    }
                }
            }
        }
Example #2
0
        private async Task RunConnectionAsync(CancellationToken connectCt, TaskCompletionSource <bool> connectTcs)
        {
            SshConnection?connection     = null;
            var           connectionInfo = new SshConnectionInfo();

            try
            {
                // Cancel when:
                // * DisposeAsync is called (_abortCts)
                // * CancellationToken parameter from ConnectAsync (connectCt)
                // * Timeout from ConnectionSettings (ConnectTimeout)
                using var connectCts = CancellationTokenSource.CreateLinkedTokenSource(connectCt, _abortCts.Token);
                connectCts.CancelAfter(_settings.ConnectTimeout);

                // Connect to the remote host
                connection = await _settings.EstablishConnectionAsync(_logger, _sequencePool, _settings, connectCts.Token);

                // Setup ssh connection
                if (!_settings.NoProtocolVersionExchange)
                {
                    await _settings.ExchangeProtocolVersionAsync(connection, connectionInfo, _logger, _settings, connectCts.Token);
                }
                if (!_settings.NoKeyExchange)
                {
                    using Packet localExchangeInitMsg = KeyExchange.CreateKeyExchangeInitMessage(_sequencePool, _logger, _settings);
                    await connection.SendPacketAsync(localExchangeInitMsg, connectCts.Token);

                    {
                        using Packet remoteExchangeInitMsg = await connection.ReceivePacketAsync(connectCts.Token);

                        if (remoteExchangeInitMsg.IsEmpty)
                        {
                            ThrowHelper.ThrowProtocolUnexpectedPeerClose();
                        }
                        await _settings.ExchangeKeysAsync(connection, localExchangeInitMsg, remoteExchangeInitMsg, _logger, _settings, connectionInfo, connectCts.Token);
                    }
                }
                if (!_settings.NoUserAuthentication)
                {
                    await _settings.AuthenticateUserAsync(connection, _logger, _settings, connectionInfo, connectCts.Token);
                }

                // Allow sending.
                _sendQueue = Channel.CreateUnbounded <PendingSend>(new UnboundedChannelOptions
                {
                    SingleWriter = false,
                    SingleReader = true,
                    AllowSynchronousContinuations = true
                });
                // Allow connection users.
                _connectionUsers = new List <Task>();
                // ConnectAsync completed successfully.
                connectTcs.SetResult(true);
            }
            catch (Exception e)
            {
                connection?.Dispose();

                // In case the operation was canceled, change the exception based on the
                // token that triggered the cancellation.
                if (e is OperationCanceledException)
                {
                    if (connectCt.IsCancellationRequested)
                    {
                        connectTcs.SetCanceled();
                        return;
                    }
                    else if (_abortCts.IsCancellationRequested)
                    {
                        e = NewObjectDisposedException();
                    }
                    else
                    {
                        e = new TimeoutException();
                    }
                }

                // ConnectAsync failed.
                connectTcs.SetException(e);
                return;
            }

            await HandleConnectionAsync(connection, connectionInfo);
        }