/** * Wait until for a condition. * * @param c Channel * @param timeout in ms, 0 means no timeout. * @param condition_mask minimum event mask (at least one of the conditions must be fulfilled) * @return all current events */ public int waitForCondition(Channel c, long timeout, int condition_mask) { boolean wasInterrupted = false; try { long end_time = 0; boolean end_time_set = false; synchronized (c) { while (true) { int current_cond = 0; int stdoutAvail = c.stdoutWritepos - c.stdoutReadpos; int stderrAvail = c.stderrWritepos - c.stderrReadpos; if (stdoutAvail > 0) current_cond = current_cond | ChannelCondition.STDOUT_DATA; if (stderrAvail > 0) current_cond = current_cond | ChannelCondition.STDERR_DATA; if (c.EOF) current_cond = current_cond | ChannelCondition.EOF; if (c.getExitStatus() != null) current_cond = current_cond | ChannelCondition.EXIT_STATUS; if (c.getExitSignal() != null) current_cond = current_cond | ChannelCondition.EXIT_SIGNAL; if (c.state == Channel.STATE_CLOSED) return current_cond | ChannelCondition.CLOSED | ChannelCondition.EOF; if ((current_cond & condition_mask) != 0) return current_cond; if (timeout > 0) { if (!end_time_set) { end_time = System.currentTimeMillis() + timeout; end_time_set = true; } else { timeout = end_time - System.currentTimeMillis(); if (timeout <= 0) return current_cond | ChannelCondition.TIMEOUT; } } try { if (timeout > 0) c.wait(timeout); else c.wait(); } catch (InterruptedException e) { wasInterrupted = true; } } } } finally { if (wasInterrupted) Thread.currentThread().interrupt(); } }
private void waitForChannelSuccessOrFailure(Channel c) throws IOException { boolean wasInterrupted = false; try { synchronized (c) { while ((c.successCounter == 0) && (c.failedCounter == 0)) { if (c.state != Channel.STATE_OPEN) { String detail = c.getReasonClosed(); if (detail == null) detail = "state: " + c.state; throw new IOException("This SSH2 channel is not open (" + detail + ")"); } try { c.wait(); } catch (InterruptedException ignore) { wasInterrupted = true; } } if (c.failedCounter != 0) { throw new IOException("The server denied the request."); } } } finally { if (wasInterrupted) Thread.currentThread().interrupt(); } }
private void waitUntilChannelOpen(Channel c) throws IOException { boolean wasInterrupted = false; synchronized (c) { while (c.state == Channel.STATE_OPENING) { try { c.wait(); } catch (InterruptedException ignore) { wasInterrupted = true; } } if (c.state != Channel.STATE_OPEN) { removeChannel(c.localID); String detail = c.getReasonClosed(); if (detail == null) detail = "state: " + c.state; throw new IOException("Could not open channel (" + detail + ")"); } } if (wasInterrupted) Thread.currentThread().interrupt(); }
public int getChannelData(Channel c, boolean extended, byte[] target, int off, int len) throws IOException { boolean wasInterrupted = false; try { int copylen = 0; int increment = 0; int remoteID = 0; int localID = 0; synchronized (c) { int stdoutAvail = 0; int stderrAvail = 0; while (true) { /* * Data available? We have to return remaining data even if the * channel is already closed. */ stdoutAvail = c.stdoutWritepos - c.stdoutReadpos; stderrAvail = c.stderrWritepos - c.stderrReadpos; if ((!extended) && (stdoutAvail != 0)) break; if ((extended) && (stderrAvail != 0)) break; /* Do not wait if more data will never arrive (EOF or CLOSED) */ if ((c.EOF) || (c.state != Channel.STATE_OPEN)) return -1; try { c.wait(); } catch (InterruptedException ignore) { wasInterrupted = true; } } /* OK, there is some data. Return it. */ if (!extended) { copylen = (stdoutAvail > len) ? len : stdoutAvail; System.arraycopy(c.stdoutBuffer, c.stdoutReadpos, target, off, copylen); c.stdoutReadpos += copylen; if (c.stdoutReadpos != c.stdoutWritepos) System.arraycopy( c.stdoutBuffer, c.stdoutReadpos, c.stdoutBuffer, 0, c.stdoutWritepos - c.stdoutReadpos); c.stdoutWritepos -= c.stdoutReadpos; c.stdoutReadpos = 0; } else { copylen = (stderrAvail > len) ? len : stderrAvail; System.arraycopy(c.stderrBuffer, c.stderrReadpos, target, off, copylen); c.stderrReadpos += copylen; if (c.stderrReadpos != c.stderrWritepos) System.arraycopy( c.stderrBuffer, c.stderrReadpos, c.stderrBuffer, 0, c.stderrWritepos - c.stderrReadpos); c.stderrWritepos -= c.stderrReadpos; c.stderrReadpos = 0; } if (c.state != Channel.STATE_OPEN) return copylen; if (c.localWindow < ((Channel.CHANNEL_BUFFER_SIZE + 1) / 2)) { int minFreeSpace = Math.min( Channel.CHANNEL_BUFFER_SIZE - c.stdoutWritepos, Channel.CHANNEL_BUFFER_SIZE - c.stderrWritepos); increment = minFreeSpace - c.localWindow; c.localWindow = minFreeSpace; } remoteID = c.remoteID; /* read while holding the lock */ localID = c.localID; /* read while holding the lock */ } /* * If a consumer reads stdout and stdin in parallel, we may end up with * sending two msgWindowAdjust messages. Luckily, it * does not matter in which order they arrive at the server. */ if (increment > 0) { log.debug( "Sending SSH_MSG_CHANNEL_WINDOW_ADJUST (channel " + localID + ", " + increment + ")"); synchronized (c.channelSendLock) { byte[] msg = c.msgWindowAdjust; msg[0] = Packets.SSH_MSG_CHANNEL_WINDOW_ADJUST; msg[1] = (byte) (remoteID >> 24); msg[2] = (byte) (remoteID >> 16); msg[3] = (byte) (remoteID >> 8); msg[4] = (byte) (remoteID); msg[5] = (byte) (increment >> 24); msg[6] = (byte) (increment >> 16); msg[7] = (byte) (increment >> 8); msg[8] = (byte) (increment); if (c.closeMessageSent == false) tm.sendMessage(msg); } } return copylen; } finally { if (wasInterrupted) Thread.currentThread().interrupt(); } }
public void sendData(Channel c, byte[] buffer, int pos, int len) throws IOException { boolean wasInterrupted = false; try { while (len > 0) { int thislen = 0; byte[] msg; synchronized (c) { while (true) { if (c.state == Channel.STATE_CLOSED) throw new ChannelClosedException( "SSH channel is closed. (" + c.getReasonClosed() + ")"); if (c.state != Channel.STATE_OPEN) throw new ChannelClosedException("SSH channel in strange state. (" + c.state + ")"); if (c.remoteWindow != 0) break; try { c.wait(); } catch (InterruptedException ignore) { wasInterrupted = true; } } /* len > 0, no sign extension can happen when comparing */ thislen = (c.remoteWindow >= len) ? len : (int) c.remoteWindow; int estimatedMaxDataLen = c.remoteMaxPacketSize - (tm.getPacketOverheadEstimate() + 9); /* The worst case scenario =) a true bottleneck */ if (estimatedMaxDataLen <= 0) { estimatedMaxDataLen = 1; } if (thislen > estimatedMaxDataLen) thislen = estimatedMaxDataLen; c.remoteWindow -= thislen; msg = new byte[1 + 8 + thislen]; msg[0] = Packets.SSH_MSG_CHANNEL_DATA; msg[1] = (byte) (c.remoteID >> 24); msg[2] = (byte) (c.remoteID >> 16); msg[3] = (byte) (c.remoteID >> 8); msg[4] = (byte) (c.remoteID); msg[5] = (byte) (thislen >> 24); msg[6] = (byte) (thislen >> 16); msg[7] = (byte) (thislen >> 8); msg[8] = (byte) (thislen); System.arraycopy(buffer, pos, msg, 9, thislen); } synchronized (c.channelSendLock) { if (c.closeMessageSent == true) throw new ChannelClosedException( "SSH channel is closed. (" + c.getReasonClosed() + ")"); tm.sendMessage(msg); } pos += thislen; len -= thislen; } } finally { if (wasInterrupted) Thread.currentThread().interrupt(); } }