KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > ch > ethz > ssh2 > channel > Channel


1
2 package ch.ethz.ssh2.channel;
3
4 /**
5  * Channel.
6  *
7  * @author Christian Plattner, plattner@inf.ethz.ch
8  * @version $Id: Channel.java,v 1.7 2005/12/07 10:25:48 cplattne Exp $
9  */

10 public class Channel
11 {
12     /*
13      * OK. Here is an important part of the JVM Specification:
14      * (http://java.sun.com/docs/books/vmspec/2nd-edition/html/Threads.doc.html#22214)
15      *
16      * Any association between locks and variables is purely conventional.
17      * Locking any lock conceptually flushes all variables from a thread's
18      * working memory, and unlocking any lock forces the writing out to main
19      * memory of all variables that the thread has assigned. That a lock may be
20      * associated with a particular object or a class is purely a convention.
21      * (...)
22      *
23      * If a thread uses a particular shared variable only after locking a
24      * particular lock and before the corresponding unlocking of that same lock,
25      * then the thread will read the shared value of that variable from main
26      * memory after the lock operation, if necessary, and will copy back to main
27      * memory the value most recently assigned to that variable before the
28      * unlock operation.
29      *
30      * This, in conjunction with the mutual exclusion rules for locks, suffices
31      * to guarantee that values are correctly transmitted from one thread to
32      * another through shared variables.
33      *
34      * ====> Always keep that in mind when modifying the Channel/ChannelManger
35      * code.
36      *
37      */

38
39     static final int STATE_OPENING = 1;
40     static final int STATE_OPEN = 2;
41     static final int STATE_CLOSED = 4;
42
43     static final int CHANNEL_BUFFER_SIZE = 30000;
44
45     /*
46      * To achieve correctness, the following rules have to be respected when
47      * accessing this object:
48      */

49
50     // These fields can always be read
51
final ChannelManager cm;
52     final ChannelOutputStream stdinStream;
53     final ChannelInputStream stdoutStream;
54     final ChannelInputStream stderrStream;
55
56     // These two fields will only be written while the Channel is in state
57
// STATE_OPENING.
58
// The code makes sure that the two fields are written out when the state is
59
// changing to STATE_OPEN.
60
// Therefore, if you know that the Channel is in state STATE_OPEN, then you
61
// can read these two fields without synchronizing on the Channel. However, make
62
// sure that you get the latest values (e.g., flush caches by synchronizing on any
63
// object). However, to be on the safe side, you can lock the channel.
64

65     int localID = -1;
66     int remoteID = -1;
67
68     /*
69      * Make sure that we never send a data/EOF/WindowChange msg after a CLOSE
70      * msg.
71      *
72      * This is a little bit complicated, but we have to do it in that way, since
73      * we cannot keep a lock on the Channel during the send operation (this
74      * would block sometimes the receiver thread, and, in extreme cases, can
75      * lead to a deadlock on both sides of the connection (senders are blocked
76      * since the receive buffers on the other side are full, and receiver
77      * threads wait for the senders to finish). It all depends on the
78      * implementation on the other side. But we cannot make any assumptions, we
79      * have to assume the worst case. Confused? Just believe me.
80      */

81
82     /*
83      * If you send a message on a channel, then you have to aquire the
84      * "channelSendLock" and check the "closeMessageSent" flag (this variable
85      * may only be accessed while holding the "channelSendLock" !!!
86      *
87      * BTW: NEVER EVER SEND MESSAGES FROM THE RECEIVE THREAD - see explanation
88      * above.
89      */

90
91     final Object JavaDoc channelSendLock = new Object JavaDoc();
92     boolean closeMessageSent = false;
93
94     /*
95      * Stop memory fragmentation by allocating this often used buffer.
96      * May only be used while holding the channelSendLock
97      */

98
99     final byte[] msgWindowAdjust = new byte[9];
100
101     // If you access (read or write) any of the following fields, then you have
102
// to synchronize on the channel.
103

104     int state = STATE_OPENING;
105
106     boolean closeMessageRecv = false;
107
108     /* This is a stupid implementation. At the moment we can only wait
109      * for one pending request per channel.
110      */

111     int successCounter = 0;
112     int failedCounter = 0;
113
114     int localWindow = 0; /* locally, we use a small window, < 2^31 */
115     long remoteWindow = 0; /* long for readable 2^32 - 1 window support */
116
117     int localMaxPacketSize = -1;
118     int remoteMaxPacketSize = -1;
119
120     final byte[] stdoutBuffer = new byte[CHANNEL_BUFFER_SIZE];
121     final byte[] stderrBuffer = new byte[CHANNEL_BUFFER_SIZE];
122
123     int stdoutReadpos = 0;
124     int stdoutWritepos = 0;
125     int stderrReadpos = 0;
126     int stderrWritepos = 0;
127
128     boolean EOF = false;
129
130     Integer JavaDoc exit_status;
131
132     String JavaDoc exit_signal;
133
134     // we keep the x11 cookie so that this channel can be closed when this
135
// specific x11 forwarding gets stopped
136

137     String JavaDoc hexX11FakeCookie;
138
139     // reasonClosed is special, since we sometimes need to access it
140
// while holding the channelSendLock.
141
// We protect it with a private short term lock.
142

143     private final Object JavaDoc reasonClosedLock = new Object JavaDoc();
144     private String JavaDoc reasonClosed = null;
145
146     public Channel(ChannelManager cm)
147     {
148         this.cm = cm;
149
150         this.localWindow = CHANNEL_BUFFER_SIZE;
151         this.localMaxPacketSize = 35000 - 1024; // leave enough slack
152

153         this.stdinStream = new ChannelOutputStream(this);
154         this.stdoutStream = new ChannelInputStream(this, false);
155         this.stderrStream = new ChannelInputStream(this, true);
156     }
157
158     /* Methods to allow access from classes outside of this package */
159
160     public ChannelInputStream getStderrStream()
161     {
162         return stderrStream;
163     }
164
165     public ChannelOutputStream getStdinStream()
166     {
167         return stdinStream;
168     }
169
170     public ChannelInputStream getStdoutStream()
171     {
172         return stdoutStream;
173     }
174
175     public String JavaDoc getExitSignal()
176     {
177         synchronized (this)
178         {
179             return exit_signal;
180         }
181     }
182
183     public Integer JavaDoc getExitStatus()
184     {
185         synchronized (this)
186         {
187             return exit_status;
188         }
189     }
190
191     public String JavaDoc getReasonClosed()
192     {
193         synchronized (reasonClosedLock)
194         {
195             return reasonClosed;
196         }
197     }
198
199     public void setReasonClosed(String JavaDoc reasonClosed)
200     {
201         synchronized (reasonClosedLock)
202         {
203             if (this.reasonClosed == null)
204                 this.reasonClosed = reasonClosed;
205         }
206     }
207 }
208
Popular Tags