Example #1
0
        private async Task ReceiveLoopAsync(SshConnection connection, SshConnectionInfo connectionInfo)
        {
            CancellationToken abortToken = _abortCts.Token;

            while (true)
            {
                var packet = await connection.ReceivePacketAsync(abortToken, maxLength : Constants.MaxPacketLength);

                if (packet.IsEmpty)
                {
                    Abort(ClosedByPeer);
                    break;
                }
                else
                {
                    // for now, eat everything.
                    packet.Dispose();
                }
                int msgType = packet.MessageType;

                // Connection Protocol: https://tools.ietf.org/html/rfc4254.

                // Dispatch to channels:
                // lock (_channels)
                // {
                //     var channelExecution = _channels[channelNumber];
                //     channelExecution.QueueReceivedPacket(packet);
                // }
                // Handle global requests
                // ...

                switch (msgType)
                {
                case MessageNumber.SSH_MSG_KEXINIT:
                    // Key Re-Exchange: https://tools.ietf.org/html/rfc4253#section-9.
                    try
                    {
                        // When we send SSH_MSG_KEXINIT, we can't send other packets until key exchange completes.
                        // This is implemented using _keyReExchangeSemaphore.
                        var keyExchangeSemaphore = new SemaphoreSlim(0, 1);
                        _keyReExchangeSemaphore = keyExchangeSemaphore;
                        // this will await _keyReExchangeSemaphore and set it to null.
                        using Packet clientKexInitMsg = KeyExchange.CreateKeyExchangeInitMessage(_sequencePool, _logger, _settings);
                        try
                        {
                            await SendPacketAsync(clientKexInitMsg, abortToken);
                        }
                        catch
                        {
                            _keyReExchangeSemaphore.Dispose();
                            _keyReExchangeSemaphore = null;
                            throw;
                        }
                        await _settings.ExchangeKeysAsync(connection, clientKexInitMsg, serverKexInitMsg : packet, _logger, _settings, connectionInfo, abortToken);

                        keyExchangeSemaphore.Release();
                    }
                    finally
                    {
                        packet.Dispose();
                    }
                    break;
                }
            }
        }
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);
        }