FerrariCalifornia commented on issue #414: URL: https://github.com/apache/mina-sshd/issues/414#issuecomment-1709350807
we did not try 2.10.0 Here is the code I suspect is causing the problem sshd-core/src/main/java/org/apache/sshd/common/session/helpers/KeyExchangeMessageHandler.java as we can see , KexState state = session.kexState.get(); when the session is already close,but key exchage not completed the code may hava an infinite loop when the debug log print `2023-09-06 16:19:59.524 [transferEpQueryReq-thread-8] DEBUG org.apache.sshd.server.session.ServerSessionImpl 282 [] writeOrEnqueue(ServerSessionImpl[itran@/200.200.60.22:47442])[SSH_MSG_CHANNEL_DATA]: Blocking thread Thread[transferEpQueryReq-thread-8,5,main] until KEX is over or timeout 10000 MILLISECONDS` i have chacked the session 200.200.60.22:47442 its already closed sshd-core/src/main/java/org/apache/sshd/common/session/helpers/KeyExchangeMessageHandler.java ``` /** * Writes an SSH packet. If no KEX is ongoing and there are no pending packets queued to be written after KEX, the * buffer is written directly. Otherwise, the write is enqueued or the calling thread is blocked until all pending * packets have been written, depending on the result of {@link #isBlockAllowed(int)}. If the calling thread holds * the monitor of the session's {@link AbstractSession#getFutureLock()}, it is never blocked and the write is * queued. * <p> * If {@code timeout <= 0} or {@code unit == null}, a time-out of "forever" is assumed. Note that a timeout applies * only if the calling thread is blocked. * </p> * * @param cmd SSH command from the buffer * @param buffer {@link Buffer} containing the packet to write * @param timeout number of {@link TimeUnit}s to wait at most if the calling thread is blocked * @param unit {@link TimeUnit} of {@code timeout} * @return an {@link IoWriteFuture} that will be fulfilled once the packet has indeed been written. * @throws IOException if an error occurs */ protected IoWriteFuture writeOrEnqueue(int cmd, Buffer buffer, long timeout, TimeUnit unit) throws IOException { boolean holdsFutureLock = Thread.holdsLock(session.getFutureLock()); for (;;) { DefaultKeyExchangeFuture block = null; // We must decide _and_ write the packet while holding the lock. If we'd write the packet outside this // lock, there is no guarantee that a concurrently running KEX_INIT received from the peer doesn't change // the state to RUN and grabs the encodeLock before the thread executing this write operation. If this // happened, we might send a high-level messages after our KEX_INIT, which is not allowed by RFC 4253. // // Use the readLock here to give KEX state updates and the flushing thread priority. lock.readLock().lock(); try { if (shutDown) { throw new SshException("Write attempt on closing session: " + SshConstants.getCommandMessageName(cmd)); } KexState state = session.kexState.get(); boolean kexDone = KexState.DONE.equals(state) || KexState.KEYS.equals(state); if (kexDone && kexFlushed) { // Not in KEX, no pending packets: out it goes. return session.doWritePacket(buffer); } else if (!holdsFutureLock && isBlockAllowed(cmd)) { // KEX done, but still flushing: block until flushing is done, if we may block. // // The future lock is a _very_ global lock used for synchronization in many futures, and in // particular in the key exchange related futures; and it is accessible by client code. If we // block a thread holding that monitor, none of the futures that use that lock can ever be // fulfilled, including the future this thread would wait upon. // // It would seem that calling writePacket() while holding *any* (session global) Apache MINA // sshd lock in client code would be extremely bad practice. But note that the deprecated // ClientUserAuthServiceOld does exactly that. While that deprecated service doesn't send // channel data, there might be client code that does similar things. But this is also the // reason why we must be careful to never synchronize on the futureLock while holding the // kexLock: if that happened while code concurrently running called writePacket() while holding // the futureLock, we might get a deadlock due to lock inversion. // // Blocking here will prevent data-pumping application threads from overrunning the flushing // thread and ensures that the flushing thread does indeed terminate. // // Note that we block only for channel data. block = kexFlushedFuture; } else { // Still in KEX or still flushing and we cannot block the thread. Enqueue the packet; it will // get written by the flushing thread at the end of KEX. Note that theoretically threads may // queue arbitrarily many packets during KEX. However, such a scenario is mostly limited to // "data pumping" threads that typically will block during KEX waiting until window space is // available on the channel again, which can happen only at the end of KEX. // (SSH_CHANNEL_WINDOW_ADJUST is not a low-level message and will not be sent during KEX.) // // If so many packets are queued that flushing them triggers another KEX flushing stops // and will be resumed at the end of the new KEX. if (kexDone && log.isDebugEnabled()) { log.debug("writeOrEnqueue({})[{}]: Queuing packet while flushing", session, SshConstants.getCommandMessageName(cmd)); } return enqueuePendingPacket(cmd, buffer); } } finally { lock.readLock().unlock(); } if (block != null) { if (timeout <= 0 || unit == null) { if (log.isDebugEnabled()) { log.debug("writeOrEnqueue({})[{}]: Blocking thread {} until KEX is over", session, SshConstants.getCommandMessageName(cmd), Thread.currentThread()); } block.await(); } else { if (log.isDebugEnabled()) { log.debug("writeOrEnqueue({})[{}]: Blocking thread {} until KEX is over or timeout {} {}", session, SshConstants.getCommandMessageName(cmd), Thread.currentThread(), timeout, unit); } block.await(timeout, unit); } if (log.isDebugEnabled()) { log.debug("writeOrEnqueue({})[{}]: Thread {} awakens after KEX done", session, SshConstants.getCommandMessageName(cmd), Thread.currentThread()); } } } } ``` -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: dev-unsubscr...@mina.apache.org For queries about this service, please contact Infrastructure at: us...@infra.apache.org --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@mina.apache.org For additional commands, e-mail: dev-h...@mina.apache.org