connect method

  1. @override
Future<SshHandshakeInfo> connect({
  1. required SshEndpoint endpoint,
  2. required SshTransportSettings settings,
})
override

Implementation

@override
Future<SshHandshakeInfo> connect({
  required SshEndpoint endpoint,
  required SshTransportSettings settings,
}) async {
  if (_state == SshTransportState.connecting ||
      _state == SshTransportState.connected) {
    throw StateError('SSH secure socket transport is already connected.');
  }

  _state = SshTransportState.connecting;
  Socket? socket;
  StreamIterator<List<int>>? incoming;

  try {
    socket = await Socket.connect(
      endpoint.host,
      endpoint.port,
      timeout: settings.connectTimeout,
    );

    if (tcpNoDelay) {
      socket.setOption(SocketOption.tcpNoDelay, true);
    }

    incoming = StreamIterator<List<int>>(socket);
    _socket = socket;
    _incoming = incoming;
    _incomingBuffer.clear();
    _packetQueue.clear();
    _pendingPacketReaders.clear();
    _pendingGlobalRequestReplies.clear();
    _writerState = SshPlainPacketWriterState();
    _readerState = SshPlainPacketReaderState();
    _incomingCompression = const _SshIdentityCompressionState();
    _outgoingCompression = const _SshIdentityCompressionState();
    _hasAuthenticated = false;
    _delayedIncomingCompressionPending = false;
    _delayedOutgoingCompressionPending = false;
    _activeRekey = null;
    _pendingClientKexInit = null;
    _outgoingPacketSequenceNumber = 0;
    _incomingPacketSequenceNumber = 0;
    _terminalError = null;
    _terminalStackTrace = null;
    _readLoop = null;

    final SshBannerExchangeResult exchange = await _exchangeBanners(
      localIdentification: settings.clientIdentification,
    );
    final SshKexInitMessage clientKexInit = _buildClientKexInit();
    await _writePlainPacket(clientKexInit.encodePayload());

    final SshKexInitMessage serverKexInit = SshKexInitMessage.decodePayload(
      (await _readPacketWithState(SshPlainPacketReaderState())).payload,
    );

    final _SshKeyExchangeResult keyExchange = await _runKeyExchangeRound(
      localIdentification: exchange.localBanner.value,
      remoteIdentification: exchange.remoteBanner.value,
      clientKexInit: clientKexInit,
      serverKexInit: serverKexInit,
      sessionIdentifier: null,
      writePacket: _writePlainPacket,
      readPacket: () => _readPacketWithState(SshPlainPacketReaderState()),
    );

    _handshake = keyExchange.handshake;
    _resetRekeyCounters();
    _state = SshTransportState.connected;
    _startReadLoop();
    return keyExchange.handshake;
  } catch (_) {
    _handshake = null;
    _state = SshTransportState.disconnected;
    await _closeResources();
    rethrow;
  }
}