aboutsummaryrefslogtreecommitdiffstats
path: root/lib/src/main/java/com/trilead/ssh2/channel/Channel.java
diff options
context:
space:
mode:
Diffstat (limited to 'lib/src/main/java/com/trilead/ssh2/channel/Channel.java')
-rw-r--r--lib/src/main/java/com/trilead/ssh2/channel/Channel.java414
1 files changed, 207 insertions, 207 deletions
diff --git a/lib/src/main/java/com/trilead/ssh2/channel/Channel.java b/lib/src/main/java/com/trilead/ssh2/channel/Channel.java
index 4b19a48..8365f12 100644
--- a/lib/src/main/java/com/trilead/ssh2/channel/Channel.java
+++ b/lib/src/main/java/com/trilead/ssh2/channel/Channel.java
@@ -1,207 +1,207 @@
-
-package com.trilead.ssh2.channel;
-
-/**
- * Channel.
- *
- * @author Christian Plattner, plattner@trilead.com
- * @version $Id: Channel.java,v 1.1 2007/10/15 12:49:56 cplattne Exp $
- */
-public class Channel
-{
- /*
- * OK. Here is an important part of the JVM Specification:
- * (http://java.sun.com/docs/books/vmspec/2nd-edition/html/Threads.doc.html#22214)
- *
- * Any association between locks and variables is purely conventional.
- * Locking any lock conceptually flushes all variables from a thread's
- * working memory, and unlocking any lock forces the writing out to main
- * memory of all variables that the thread has assigned. That a lock may be
- * associated with a particular object or a class is purely a convention.
- * (...)
- *
- * If a thread uses a particular shared variable only after locking a
- * particular lock and before the corresponding unlocking of that same lock,
- * then the thread will read the shared value of that variable from main
- * memory after the lock operation, if necessary, and will copy back to main
- * memory the value most recently assigned to that variable before the
- * unlock operation.
- *
- * This, in conjunction with the mutual exclusion rules for locks, suffices
- * to guarantee that values are correctly transmitted from one thread to
- * another through shared variables.
- *
- * ====> Always keep that in mind when modifying the Channel/ChannelManger
- * code.
- *
- */
-
- static final int STATE_OPENING = 1;
- static final int STATE_OPEN = 2;
- static final int STATE_CLOSED = 4;
-
- static final int CHANNEL_BUFFER_SIZE = 30000;
-
- /*
- * To achieve correctness, the following rules have to be respected when
- * accessing this object:
- */
-
- // These fields can always be read
- final ChannelManager cm;
- final ChannelOutputStream stdinStream;
- final ChannelInputStream stdoutStream;
- final ChannelInputStream stderrStream;
-
- // These two fields will only be written while the Channel is in state
- // STATE_OPENING.
- // The code makes sure that the two fields are written out when the state is
- // changing to STATE_OPEN.
- // Therefore, if you know that the Channel is in state STATE_OPEN, then you
- // can read these two fields without synchronizing on the Channel. However, make
- // sure that you get the latest values (e.g., flush caches by synchronizing on any
- // object). However, to be on the safe side, you can lock the channel.
-
- int localID = -1;
- int remoteID = -1;
-
- /*
- * Make sure that we never send a data/EOF/WindowChange msg after a CLOSE
- * msg.
- *
- * This is a little bit complicated, but we have to do it in that way, since
- * we cannot keep a lock on the Channel during the send operation (this
- * would block sometimes the receiver thread, and, in extreme cases, can
- * lead to a deadlock on both sides of the connection (senders are blocked
- * since the receive buffers on the other side are full, and receiver
- * threads wait for the senders to finish). It all depends on the
- * implementation on the other side. But we cannot make any assumptions, we
- * have to assume the worst case. Confused? Just believe me.
- */
-
- /*
- * If you send a message on a channel, then you have to aquire the
- * "channelSendLock" and check the "closeMessageSent" flag (this variable
- * may only be accessed while holding the "channelSendLock" !!!
- *
- * BTW: NEVER EVER SEND MESSAGES FROM THE RECEIVE THREAD - see explanation
- * above.
- */
-
- final Object channelSendLock = new Object();
- boolean closeMessageSent = false;
-
- /*
- * Stop memory fragmentation by allocating this often used buffer.
- * May only be used while holding the channelSendLock
- */
-
- final byte[] msgWindowAdjust = new byte[9];
-
- // If you access (read or write) any of the following fields, then you have
- // to synchronize on the channel.
-
- int state = STATE_OPENING;
-
- boolean closeMessageRecv = false;
-
- /* This is a stupid implementation. At the moment we can only wait
- * for one pending request per channel.
- */
- int successCounter = 0;
- int failedCounter = 0;
-
- int localWindow = 0; /* locally, we use a small window, < 2^31 */
- long remoteWindow = 0; /* long for readable 2^32 - 1 window support */
-
- int localMaxPacketSize = -1;
- int remoteMaxPacketSize = -1;
-
- final byte[] stdoutBuffer = new byte[CHANNEL_BUFFER_SIZE];
- final byte[] stderrBuffer = new byte[CHANNEL_BUFFER_SIZE];
-
- int stdoutReadpos = 0;
- int stdoutWritepos = 0;
- int stderrReadpos = 0;
- int stderrWritepos = 0;
-
- boolean EOF = false;
-
- Integer exit_status;
-
- String exit_signal;
-
- // we keep the x11 cookie so that this channel can be closed when this
- // specific x11 forwarding gets stopped
-
- String hexX11FakeCookie;
-
- // reasonClosed is special, since we sometimes need to access it
- // while holding the channelSendLock.
- // We protect it with a private short term lock.
-
- private final Object reasonClosedLock = new Object();
- private String reasonClosed = null;
-
- public Channel(ChannelManager cm)
- {
- this.cm = cm;
-
- this.localWindow = CHANNEL_BUFFER_SIZE;
- this.localMaxPacketSize = 35000 - 1024; // leave enough slack
-
- this.stdinStream = new ChannelOutputStream(this);
- this.stdoutStream = new ChannelInputStream(this, false);
- this.stderrStream = new ChannelInputStream(this, true);
- }
-
- /* Methods to allow access from classes outside of this package */
-
- public ChannelInputStream getStderrStream()
- {
- return stderrStream;
- }
-
- public ChannelOutputStream getStdinStream()
- {
- return stdinStream;
- }
-
- public ChannelInputStream getStdoutStream()
- {
- return stdoutStream;
- }
-
- public String getExitSignal()
- {
- synchronized (this)
- {
- return exit_signal;
- }
- }
-
- public Integer getExitStatus()
- {
- synchronized (this)
- {
- return exit_status;
- }
- }
-
- public String getReasonClosed()
- {
- synchronized (reasonClosedLock)
- {
- return reasonClosed;
- }
- }
-
- public void setReasonClosed(String reasonClosed)
- {
- synchronized (reasonClosedLock)
- {
- if (this.reasonClosed == null)
- this.reasonClosed = reasonClosed;
- }
- }
-}
+
+package com.trilead.ssh2.channel;
+
+/**
+ * Channel.
+ *
+ * @author Christian Plattner, plattner@trilead.com
+ * @version $Id: Channel.java,v 1.1 2007/10/15 12:49:56 cplattne Exp $
+ */
+public class Channel
+{
+ /*
+ * OK. Here is an important part of the JVM Specification:
+ * (http://java.sun.com/docs/books/vmspec/2nd-edition/html/Threads.doc.html#22214)
+ *
+ * Any association between locks and variables is purely conventional.
+ * Locking any lock conceptually flushes all variables from a thread's
+ * working memory, and unlocking any lock forces the writing out to main
+ * memory of all variables that the thread has assigned. That a lock may be
+ * associated with a particular object or a class is purely a convention.
+ * (...)
+ *
+ * If a thread uses a particular shared variable only after locking a
+ * particular lock and before the corresponding unlocking of that same lock,
+ * then the thread will read the shared value of that variable from main
+ * memory after the lock operation, if necessary, and will copy back to main
+ * memory the value most recently assigned to that variable before the
+ * unlock operation.
+ *
+ * This, in conjunction with the mutual exclusion rules for locks, suffices
+ * to guarantee that values are correctly transmitted from one thread to
+ * another through shared variables.
+ *
+ * ====> Always keep that in mind when modifying the Channel/ChannelManger
+ * code.
+ *
+ */
+
+ static final int STATE_OPENING = 1;
+ static final int STATE_OPEN = 2;
+ static final int STATE_CLOSED = 4;
+
+ static final int CHANNEL_BUFFER_SIZE = 30000;
+
+ /*
+ * To achieve correctness, the following rules have to be respected when
+ * accessing this object:
+ */
+
+ // These fields can always be read
+ final ChannelManager cm;
+ final ChannelOutputStream stdinStream;
+ final ChannelInputStream stdoutStream;
+ final ChannelInputStream stderrStream;
+
+ // These two fields will only be written while the Channel is in state
+ // STATE_OPENING.
+ // The code makes sure that the two fields are written out when the state is
+ // changing to STATE_OPEN.
+ // Therefore, if you know that the Channel is in state STATE_OPEN, then you
+ // can read these two fields without synchronizing on the Channel. However, make
+ // sure that you get the latest values (e.g., flush caches by synchronizing on any
+ // object). However, to be on the safe side, you can lock the channel.
+
+ int localID = -1;
+ int remoteID = -1;
+
+ /*
+ * Make sure that we never send a data/EOF/WindowChange msg after a CLOSE
+ * msg.
+ *
+ * This is a little bit complicated, but we have to do it in that way, since
+ * we cannot keep a lock on the Channel during the send operation (this
+ * would block sometimes the receiver thread, and, in extreme cases, can
+ * lead to a deadlock on both sides of the connection (senders are blocked
+ * since the receive buffers on the other side are full, and receiver
+ * threads wait for the senders to finish). It all depends on the
+ * implementation on the other side. But we cannot make any assumptions, we
+ * have to assume the worst case. Confused? Just believe me.
+ */
+
+ /*
+ * If you send a message on a channel, then you have to aquire the
+ * "channelSendLock" and check the "closeMessageSent" flag (this variable
+ * may only be accessed while holding the "channelSendLock" !!!
+ *
+ * BTW: NEVER EVER SEND MESSAGES FROM THE RECEIVE THREAD - see explanation
+ * above.
+ */
+
+ final Object channelSendLock = new Object();
+ boolean closeMessageSent = false;
+
+ /*
+ * Stop memory fragmentation by allocating this often used buffer.
+ * May only be used while holding the channelSendLock
+ */
+
+ final byte[] msgWindowAdjust = new byte[9];
+
+ // If you access (read or write) any of the following fields, then you have
+ // to synchronize on the channel.
+
+ int state = STATE_OPENING;
+
+ boolean closeMessageRecv = false;
+
+ /* This is a stupid implementation. At the moment we can only wait
+ * for one pending request per channel.
+ */
+ int successCounter = 0;
+ int failedCounter = 0;
+
+ int localWindow = 0; /* locally, we use a small window, < 2^31 */
+ long remoteWindow = 0; /* long for readable 2^32 - 1 window support */
+
+ int localMaxPacketSize = -1;
+ int remoteMaxPacketSize = -1;
+
+ final byte[] stdoutBuffer = new byte[CHANNEL_BUFFER_SIZE];
+ final byte[] stderrBuffer = new byte[CHANNEL_BUFFER_SIZE];
+
+ int stdoutReadpos = 0;
+ int stdoutWritepos = 0;
+ int stderrReadpos = 0;
+ int stderrWritepos = 0;
+
+ boolean EOF = false;
+
+ Integer exit_status;
+
+ String exit_signal;
+
+ // we keep the x11 cookie so that this channel can be closed when this
+ // specific x11 forwarding gets stopped
+
+ String hexX11FakeCookie;
+
+ // reasonClosed is special, since we sometimes need to access it
+ // while holding the channelSendLock.
+ // We protect it with a private short term lock.
+
+ private final Object reasonClosedLock = new Object();
+ private String reasonClosed = null;
+
+ public Channel(ChannelManager cm)
+ {
+ this.cm = cm;
+
+ this.localWindow = CHANNEL_BUFFER_SIZE;
+ this.localMaxPacketSize = 35000 - 1024; // leave enough slack
+
+ this.stdinStream = new ChannelOutputStream(this);
+ this.stdoutStream = new ChannelInputStream(this, false);
+ this.stderrStream = new ChannelInputStream(this, true);
+ }
+
+ /* Methods to allow access from classes outside of this package */
+
+ public ChannelInputStream getStderrStream()
+ {
+ return stderrStream;
+ }
+
+ public ChannelOutputStream getStdinStream()
+ {
+ return stdinStream;
+ }
+
+ public ChannelInputStream getStdoutStream()
+ {
+ return stdoutStream;
+ }
+
+ public String getExitSignal()
+ {
+ synchronized (this)
+ {
+ return exit_signal;
+ }
+ }
+
+ public Integer getExitStatus()
+ {
+ synchronized (this)
+ {
+ return exit_status;
+ }
+ }
+
+ public String getReasonClosed()
+ {
+ synchronized (reasonClosedLock)
+ {
+ return reasonClosed;
+ }
+ }
+
+ public void setReasonClosed(String reasonClosed)
+ {
+ synchronized (reasonClosedLock)
+ {
+ if (this.reasonClosed == null)
+ this.reasonClosed = reasonClosed;
+ }
+ }
+}