2017-01-13 44 views
12

Uygulamamız için SftpConnections Havuzu'nu uygulamaya çalışırken bir sorun yaşıyoruz.SSH Sunucu Kimliği hiçbir zaman alınmadı - Handshake Deadlock [SSHJ]

Şu anda kullandığınız

SSHJ taşıma kitaplık olarak (Schmizz) ve biz sadece bizim geliştirme ortamında taklit edemez bir sorunla karşı karşıya (ama hata bazen sadece 10 dakika sonra, bazen üç gün sonra, üretimde rastgele gösteren tutar).

SFTP yoluyla dosya göndermeye çalışırken sorun, iplik TransportImpl sınıfından 'schmizz gelen init yöntemde kilitli alır edilir:

@Override 
    public void init(String remoteHost, int remotePort, InputStream in, OutputStream out) 
      throws TransportException { 
     connInfo = new ConnInfo(remoteHost, remotePort, in, out); 

    try { 

     if (config.isWaitForServerIdentBeforeSendingClientIdent()) { 
      receiveServerIdent(); 
      sendClientIdent(); 
     } else { 
      sendClientIdent(); 
      receiveServerIdent(); 
     } 


     log.info("Server identity string: {}", serverID); 

    } catch (IOException e) { 
     throw new TransportException(e); 
    } 

    reader.start(); 
} 

isWaitForServerIdentBeforeSendingClientIdent yüzden her şeyden önce, bizim için YANLıŞ'tır

: günlükleri göründüğü gibi istemci (biz), bizim kimlik gönder "Müşteri kimlik dize: blabla"

Sonra receiveServerIdent için dönüş var: Sunucu asla kimliği ile cevap olarak

private void receiveServerIdent() throws IOException 
{ 
     final Buffer.PlainBuffer buf = new Buffer.PlainBuffer(); 
     while ((serverID = readIdentification(buf)).isEmpty()) { 
      int b = connInfo.in.read(); 
      if (b == -1) 
       throw new TransportException("Server closed connection during identification exchange"); 
      buf.putByte((byte) b); 
     } 
    } 

iplik, kontrol yine geçmez. Kod bu Süre döngüde sıkışmış gibi görünüyor. Hiçbir zaman aşımı veya SSH istisnası atılmaz, müvekkilim sonsuza kadar beklemeye devam ediyor ve iş parçacığı kilitlenmiyor.

Bu

readIdentification yöntemin impl geçerli:

private String readIdentification(Buffer.PlainBuffer buffer) 
     throws IOException { 
    String ident = new IdentificationStringParser(buffer, loggerFactory).parseIdentificationString(); 
    if (ident.isEmpty()) { 
     return ident; 
    } 

    if (!ident.startsWith("SSH-2.0-") && !ident.startsWith("SSH-1.99-")) 
     throw new TransportException(DisconnectReason.PROTOCOL_VERSION_NOT_SUPPORTED, 
            "Server does not support SSHv2, identified as: " + ident); 

    return ident; 
} 

sunucu bağlantıyı kesti sanki veri okumayı geçmez ConnectionInfo en inputStream gibi görünüyor (bile daha önce söylediği gibi, hiçbir istisnası atılır) .

Bu hatayı, bağlantı yaparken yuvaları kapatarak, bağlantıyı kapatırken, el sıkışma yapılırken kurulan bağlantıları öldürmek için conntrack kullanarak, bu yüzden herhangi bir yardım YÜKSEK takdir edildim .

:

String ident = new IdentificationStringParser(buffer, loggerFactory).parseIdentificationString(); 
if (ident.isEmpty()) { 
    return ident; 
} 

IdentificationStringParser.parseIdentificationString() boş bir dize döndürür, bu arayanın yöntemine iade edilecektir:)

+0

'waitForServerIdent' bayrağını true olarak ayarlamayı denediniz mi? Bağlandığınız SSH sunucu türü nedir? –

+0

İplik dökümü araştırdınız mı? –

+0

Hiery Nomus: Siparişi ve bir SFTP sunucusunu değiştirirken bir fark yok. :) Vladislav: İş parçacığı dökümü, söz konusu bölümde bir kilitlenme gösteriyor: sunucudan yanıt alınmıyor, bu nedenle program sonsuza dek durdu ... kod sorunu değil. –

cevap

1

kod aşağıdaki bahis bir sorun yaratır. Arayan metodu, her zaman boş olduğundan while ((serverID = readIdentification(buf)).isEmpty())'u aramaya devam edecektir. Döngüyü kesmenin tek yolu, int b = connInfo.in.read(); numaralı çağrıya -1 döndürürse, ancak sunucu verileri göndermeye devam ederse (veya verileri yeniden gönderirse) bu koşul asla karşılanmaz.

bu ben algılamak için yapay bir şekilde bir tür eklersiniz durumda böyle:

private String readIdentification(Buffer.PlainBuffer buffer, AtomicInteger numberOfAttempts) 
     throws IOException { 
    String ident = new IdentificationStringParser(buffer, loggerFactory).parseIdentificationString(); 

    numberOfAttempts.incrementAndGet(); 


    if (ident.isEmpty() && numberOfAttempts.intValue() < 1000) { // 1000 
     return ident; 
    } else if (numberOfAttempts.intValue() >= 1000) { 
     throw new TransportException("To many attempts to read the server ident"). 

    } 

    if (!ident.startsWith("SSH-2.0-") && !ident.startsWith("SSH-1.99-")) 
     throw new TransportException(DisconnectReason.PROTOCOL_VERSION_NOT_SUPPORTED, 
            "Server does not support SSHv2, identified as: " + ident); 

    return ident; 
} 

en azından bu durumda olduğunu teyit ediyorum ve daha fazla kazmak Bu şekilde neden .parseIdentificationString() boş dize döndürür.