view src/com/trilead/ssh2/channel/Channel.java @ 21:94abfc6441a4
tn5250
adding tn5250 files
author
Carl Byington <carl@five-ten-sg.com>
date
Tue, 03 Jun 2014 10:29:26 -0700 (2014-06-03)
parents
0ce5cc452d02
children
line source
+ −
+ − 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;
+ − }
+ − }
+ − }