Mercurial > 510Connectbot
diff src/ch/ethz/ssh2/channel/Channel.java @ 308:42b15aaa7ac7 ganymed
merge
author | Carl Byington <carl@five-ten-sg.com> |
---|---|
date | Wed, 30 Jul 2014 14:21:50 -0700 |
parents | 071eccdff8ea |
children |
line wrap: on
line diff
--- a/src/ch/ethz/ssh2/channel/Channel.java Wed Jul 30 13:38:04 2014 -0700 +++ b/src/ch/ethz/ssh2/channel/Channel.java Wed Jul 30 14:21:50 2014 -0700 @@ -14,208 +14,192 @@ * @author Christian Plattner * @version $Id: Channel.java 123 2014-04-12 21:11:47Z dkocher@sudo.ch $ */ -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. - * - */ +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. + * + */ - public static final int STATE_OPENING = 1; - public static final int STATE_OPEN = 2; - public static final int STATE_CLOSED = 4; + public static final int STATE_OPENING = 1; + public static final int STATE_OPEN = 2; + public static final int STATE_CLOSED = 4; - static final int CHANNEL_BUFFER_SIZE = 32 * 1024 * 3 * 2; + static final int CHANNEL_BUFFER_SIZE = 32 * 1024 * 3 * 2; - /* - * To achieve correctness, the following rules have to be respected when - * accessing this object: - */ + /* + * 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; - - // In case this channel belongs to a server-side session. - ServerSessionImpl ss; + // 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; + // In case this channel belongs to a server-side session. + ServerSessionImpl ss; - /* - * 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. - */ + // 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; - /* - * 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; + /* + * 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. + */ - /* - * 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 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. + */ - // If you access (read or write) any of the following fields, then you have - // to synchronize on the channel. + final Object channelSendLock = new Object(); + boolean closeMessageSent = false; - int state = STATE_OPENING; + /* + * Stop memory fragmentation by allocating this often used buffer. + * May only be used while holding the channelSendLock + */ - boolean closeMessageRecv = false; + final byte[] msgWindowAdjust = new byte[9]; - /* This is a stupid implementation. At the moment we can only wait - * for one pending request per channel. - */ - int successCounter = 0; - int failedCounter = 0; + // If you access (read or write) any of the following fields, then you have + // to synchronize on the channel. - int localWindow = 0; /* locally, we use a small window, < 2^31 */ - long remoteWindow = 0; /* long for readable 2^32 - 1 window support */ + int state = STATE_OPENING; - int localMaxPacketSize = -1; - int remoteMaxPacketSize = -1; + boolean closeMessageRecv = false; - final byte[] stdoutBuffer = new byte[CHANNEL_BUFFER_SIZE]; - final byte[] stderrBuffer = new byte[CHANNEL_BUFFER_SIZE]; + /* 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 stdoutReadpos = 0; - int stdoutWritepos = 0; - int stderrReadpos = 0; - int stderrWritepos = 0; + int localWindow = 0; /* locally, we use a small window, < 2^31 */ + long remoteWindow = 0; /* long for readable 2^32 - 1 window support */ - boolean EOF = false; + int localMaxPacketSize = -1; + int remoteMaxPacketSize = -1; - Integer exit_status; - - String exit_signal; + final byte[] stdoutBuffer = new byte[CHANNEL_BUFFER_SIZE]; + final byte[] stderrBuffer = new byte[CHANNEL_BUFFER_SIZE]; - // we keep the x11 cookie so that this channel can be closed when this - // specific x11 forwarding gets stopped - - String hexX11FakeCookie; + int stdoutReadpos = 0; + int stdoutWritepos = 0; + int stderrReadpos = 0; + int stderrWritepos = 0; - // reasonClosed is special, since we sometimes need to access it - // while holding the channelSendLock. - // We protect it with a private short term lock. + boolean EOF = false; - private final Object reasonClosedLock = new Object(); - private IOException reasonClosed = null; + Integer exit_status; + + String exit_signal; - public Channel(ChannelManager cm) - { - this.cm = cm; + // we keep the x11 cookie so that this channel can be closed when this + // specific x11 forwarding gets stopped - this.localWindow = CHANNEL_BUFFER_SIZE; - this.localMaxPacketSize = TransportManager.MAX_PACKET_SIZE; + String hexX11FakeCookie; - this.stdinStream = new ChannelOutputStream(this); - this.stdoutStream = new ChannelInputStream(this, false); - this.stderrStream = new ChannelInputStream(this, true); - } + // reasonClosed is special, since we sometimes need to access it + // while holding the channelSendLock. + // We protect it with a private short term lock. - /* Methods to allow access from classes outside of this package */ + private final Object reasonClosedLock = new Object(); + private IOException reasonClosed = null; - public ChannelInputStream getStderrStream() - { - return stderrStream; - } + public Channel(ChannelManager cm) { + this.cm = cm; + this.localWindow = CHANNEL_BUFFER_SIZE; + this.localMaxPacketSize = TransportManager.MAX_PACKET_SIZE; + this.stdinStream = new ChannelOutputStream(this); + this.stdoutStream = new ChannelInputStream(this, false); + this.stderrStream = new ChannelInputStream(this, true); + } - public ChannelOutputStream getStdinStream() - { - return stdinStream; - } + /* Methods to allow access from classes outside of this package */ - public ChannelInputStream getStdoutStream() - { - return stdoutStream; - } + public ChannelInputStream getStderrStream() { + return stderrStream; + } - public String getExitSignal() - { - synchronized (this) - { - return exit_signal; - } - } + public ChannelOutputStream getStdinStream() { + return stdinStream; + } + + public ChannelInputStream getStdoutStream() { + return stdoutStream; + } - public Integer getExitStatus() - { - synchronized (this) - { - return exit_status; - } - } + public String getExitSignal() { + synchronized (this) { + return exit_signal; + } + } + + public Integer getExitStatus() { + synchronized (this) { + return exit_status; + } + } - public IOException getReasonClosed() - { - synchronized (reasonClosedLock) - { - return reasonClosed; - } - } + public IOException getReasonClosed() { + synchronized (reasonClosedLock) { + return reasonClosed; + } + } - public void setReasonClosed(IOException e) - { - synchronized (reasonClosedLock) - { + public void setReasonClosed(IOException e) { + synchronized (reasonClosedLock) { this.reasonClosed = e; - } - } + } + } - public int getState() - { - return this.state; - } + public int getState() { + return this.state; + } }