comparison 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
comparison
equal deleted inserted replaced
306:90e47d99ea54 308:42b15aaa7ac7
12 * Channel. 12 * Channel.
13 * 13 *
14 * @author Christian Plattner 14 * @author Christian Plattner
15 * @version $Id: Channel.java 123 2014-04-12 21:11:47Z dkocher@sudo.ch $ 15 * @version $Id: Channel.java 123 2014-04-12 21:11:47Z dkocher@sudo.ch $
16 */ 16 */
17 public class Channel 17 public class Channel {
18 { 18 /*
19 /* 19 * OK. Here is an important part of the JVM Specification:
20 * OK. Here is an important part of the JVM Specification: 20 * (http://java.sun.com/docs/books/vmspec/2nd-edition/html/Threads.doc.html#22214)
21 * (http://java.sun.com/docs/books/vmspec/2nd-edition/html/Threads.doc.html#22214) 21 *
22 * 22 * Any association between locks and variables is purely conventional.
23 * Any association between locks and variables is purely conventional. 23 * Locking any lock conceptually flushes all variables from a thread's
24 * Locking any lock conceptually flushes all variables from a thread's 24 * working memory, and unlocking any lock forces the writing out to main
25 * working memory, and unlocking any lock forces the writing out to main 25 * memory of all variables that the thread has assigned. That a lock may be
26 * memory of all variables that the thread has assigned. That a lock may be 26 * associated with a particular object or a class is purely a convention.
27 * associated with a particular object or a class is purely a convention. 27 * (...)
28 * (...) 28 *
29 * 29 * If a thread uses a particular shared variable only after locking a
30 * If a thread uses a particular shared variable only after locking a 30 * particular lock and before the corresponding unlocking of that same lock,
31 * particular lock and before the corresponding unlocking of that same lock, 31 * then the thread will read the shared value of that variable from main
32 * then the thread will read the shared value of that variable from main 32 * memory after the lock operation, if necessary, and will copy back to main
33 * memory after the lock operation, if necessary, and will copy back to main 33 * memory the value most recently assigned to that variable before the
34 * memory the value most recently assigned to that variable before the 34 * unlock operation.
35 * unlock operation. 35 *
36 * 36 * This, in conjunction with the mutual exclusion rules for locks, suffices
37 * This, in conjunction with the mutual exclusion rules for locks, suffices 37 * to guarantee that values are correctly transmitted from one thread to
38 * to guarantee that values are correctly transmitted from one thread to 38 * another through shared variables.
39 * another through shared variables. 39 *
40 * 40 * ====> Always keep that in mind when modifying the Channel/ChannelManger
41 * ====> Always keep that in mind when modifying the Channel/ChannelManger 41 * code.
42 * code. 42 *
43 * 43 */
44 */ 44
45 45 public static final int STATE_OPENING = 1;
46 public static final int STATE_OPENING = 1; 46 public static final int STATE_OPEN = 2;
47 public static final int STATE_OPEN = 2; 47 public static final int STATE_CLOSED = 4;
48 public static final int STATE_CLOSED = 4; 48
49 49 static final int CHANNEL_BUFFER_SIZE = 32 * 1024 * 3 * 2;
50 static final int CHANNEL_BUFFER_SIZE = 32 * 1024 * 3 * 2; 50
51 51 /*
52 /* 52 * To achieve correctness, the following rules have to be respected when
53 * To achieve correctness, the following rules have to be respected when 53 * accessing this object:
54 * accessing this object: 54 */
55 */ 55
56 56 // These fields can always be read
57 // These fields can always be read 57 final ChannelManager cm;
58 final ChannelManager cm; 58 final ChannelOutputStream stdinStream;
59 final ChannelOutputStream stdinStream; 59 final ChannelInputStream stdoutStream;
60 final ChannelInputStream stdoutStream; 60 final ChannelInputStream stderrStream;
61 final ChannelInputStream stderrStream; 61
62 62 // In case this channel belongs to a server-side session.
63 // In case this channel belongs to a server-side session. 63 ServerSessionImpl ss;
64 ServerSessionImpl ss; 64
65 65 // These two fields will only be written while the Channel is in state
66 // These two fields will only be written while the Channel is in state 66 // STATE_OPENING.
67 // STATE_OPENING. 67 // The code makes sure that the two fields are written out when the state is
68 // The code makes sure that the two fields are written out when the state is 68 // changing to STATE_OPEN.
69 // changing to STATE_OPEN. 69 // Therefore, if you know that the Channel is in state STATE_OPEN, then you
70 // Therefore, if you know that the Channel is in state STATE_OPEN, then you 70 // can read these two fields without synchronizing on the Channel. However, make
71 // can read these two fields without synchronizing on the Channel. However, make 71 // sure that you get the latest values (e.g., flush caches by synchronizing on any
72 // sure that you get the latest values (e.g., flush caches by synchronizing on any 72 // object). However, to be on the safe side, you can lock the channel.
73 // object). However, to be on the safe side, you can lock the channel. 73
74 74 int localID = -1;
75 int localID = -1; 75 int remoteID = -1;
76 int remoteID = -1; 76
77 77 /*
78 /* 78 * Make sure that we never send a data/EOF/WindowChange msg after a CLOSE
79 * Make sure that we never send a data/EOF/WindowChange msg after a CLOSE 79 * msg.
80 * msg. 80 *
81 * 81 * This is a little bit complicated, but we have to do it in that way, since
82 * This is a little bit complicated, but we have to do it in that way, since 82 * we cannot keep a lock on the Channel during the send operation (this
83 * we cannot keep a lock on the Channel during the send operation (this 83 * would block sometimes the receiver thread, and, in extreme cases, can
84 * would block sometimes the receiver thread, and, in extreme cases, can 84 * lead to a deadlock on both sides of the connection (senders are blocked
85 * lead to a deadlock on both sides of the connection (senders are blocked 85 * since the receive buffers on the other side are full, and receiver
86 * since the receive buffers on the other side are full, and receiver 86 * threads wait for the senders to finish). It all depends on the
87 * threads wait for the senders to finish). It all depends on the 87 * implementation on the other side. But we cannot make any assumptions, we
88 * implementation on the other side. But we cannot make any assumptions, we 88 * have to assume the worst case. Confused? Just believe me.
89 * have to assume the worst case. Confused? Just believe me. 89 */
90 */ 90
91 91 /*
92 /* 92 * If you send a message on a channel, then you have to aquire the
93 * If you send a message on a channel, then you have to aquire the 93 * "channelSendLock" and check the "closeMessageSent" flag (this variable
94 * "channelSendLock" and check the "closeMessageSent" flag (this variable 94 * may only be accessed while holding the "channelSendLock" !!!
95 * may only be accessed while holding the "channelSendLock" !!! 95 *
96 * 96 * BTW: NEVER EVER SEND MESSAGES FROM THE RECEIVE THREAD - see explanation
97 * BTW: NEVER EVER SEND MESSAGES FROM THE RECEIVE THREAD - see explanation 97 * above.
98 * above. 98 */
99 */ 99
100 100 final Object channelSendLock = new Object();
101 final Object channelSendLock = new Object(); 101 boolean closeMessageSent = false;
102 boolean closeMessageSent = false; 102
103 103 /*
104 /* 104 * Stop memory fragmentation by allocating this often used buffer.
105 * Stop memory fragmentation by allocating this often used buffer. 105 * May only be used while holding the channelSendLock
106 * May only be used while holding the channelSendLock 106 */
107 */ 107
108 108 final byte[] msgWindowAdjust = new byte[9];
109 final byte[] msgWindowAdjust = new byte[9]; 109
110 110 // If you access (read or write) any of the following fields, then you have
111 // If you access (read or write) any of the following fields, then you have 111 // to synchronize on the channel.
112 // to synchronize on the channel. 112
113 113 int state = STATE_OPENING;
114 int state = STATE_OPENING; 114
115 115 boolean closeMessageRecv = false;
116 boolean closeMessageRecv = false; 116
117 117 /* This is a stupid implementation. At the moment we can only wait
118 /* This is a stupid implementation. At the moment we can only wait 118 * for one pending request per channel.
119 * for one pending request per channel. 119 */
120 */ 120 int successCounter = 0;
121 int successCounter = 0; 121 int failedCounter = 0;
122 int failedCounter = 0; 122
123 123 int localWindow = 0; /* locally, we use a small window, < 2^31 */
124 int localWindow = 0; /* locally, we use a small window, < 2^31 */ 124 long remoteWindow = 0; /* long for readable 2^32 - 1 window support */
125 long remoteWindow = 0; /* long for readable 2^32 - 1 window support */ 125
126 126 int localMaxPacketSize = -1;
127 int localMaxPacketSize = -1; 127 int remoteMaxPacketSize = -1;
128 int remoteMaxPacketSize = -1; 128
129 129 final byte[] stdoutBuffer = new byte[CHANNEL_BUFFER_SIZE];
130 final byte[] stdoutBuffer = new byte[CHANNEL_BUFFER_SIZE]; 130 final byte[] stderrBuffer = new byte[CHANNEL_BUFFER_SIZE];
131 final byte[] stderrBuffer = new byte[CHANNEL_BUFFER_SIZE]; 131
132 132 int stdoutReadpos = 0;
133 int stdoutReadpos = 0; 133 int stdoutWritepos = 0;
134 int stdoutWritepos = 0; 134 int stderrReadpos = 0;
135 int stderrReadpos = 0; 135 int stderrWritepos = 0;
136 int stderrWritepos = 0; 136
137 137 boolean EOF = false;
138 boolean EOF = false; 138
139 139 Integer exit_status;
140 Integer exit_status; 140
141 141 String exit_signal;
142 String exit_signal; 142
143 143 // we keep the x11 cookie so that this channel can be closed when this
144 // we keep the x11 cookie so that this channel can be closed when this 144 // specific x11 forwarding gets stopped
145 // specific x11 forwarding gets stopped 145
146 146 String hexX11FakeCookie;
147 String hexX11FakeCookie; 147
148 148 // reasonClosed is special, since we sometimes need to access it
149 // reasonClosed is special, since we sometimes need to access it 149 // while holding the channelSendLock.
150 // while holding the channelSendLock. 150 // We protect it with a private short term lock.
151 // We protect it with a private short term lock. 151
152 152 private final Object reasonClosedLock = new Object();
153 private final Object reasonClosedLock = new Object(); 153 private IOException reasonClosed = null;
154 private IOException reasonClosed = null; 154
155 155 public Channel(ChannelManager cm) {
156 public Channel(ChannelManager cm) 156 this.cm = cm;
157 { 157 this.localWindow = CHANNEL_BUFFER_SIZE;
158 this.cm = cm;
159
160 this.localWindow = CHANNEL_BUFFER_SIZE;
161 this.localMaxPacketSize = TransportManager.MAX_PACKET_SIZE; 158 this.localMaxPacketSize = TransportManager.MAX_PACKET_SIZE;
162 159 this.stdinStream = new ChannelOutputStream(this);
163 this.stdinStream = new ChannelOutputStream(this); 160 this.stdoutStream = new ChannelInputStream(this, false);
164 this.stdoutStream = new ChannelInputStream(this, false); 161 this.stderrStream = new ChannelInputStream(this, true);
165 this.stderrStream = new ChannelInputStream(this, true); 162 }
166 } 163
167 164 /* Methods to allow access from classes outside of this package */
168 /* Methods to allow access from classes outside of this package */ 165
169 166 public ChannelInputStream getStderrStream() {
170 public ChannelInputStream getStderrStream() 167 return stderrStream;
171 { 168 }
172 return stderrStream; 169
173 } 170 public ChannelOutputStream getStdinStream() {
174 171 return stdinStream;
175 public ChannelOutputStream getStdinStream() 172 }
176 { 173
177 return stdinStream; 174 public ChannelInputStream getStdoutStream() {
178 } 175 return stdoutStream;
179 176 }
180 public ChannelInputStream getStdoutStream() 177
181 { 178 public String getExitSignal() {
182 return stdoutStream; 179 synchronized (this) {
183 } 180 return exit_signal;
184 181 }
185 public String getExitSignal() 182 }
186 { 183
187 synchronized (this) 184 public Integer getExitStatus() {
188 { 185 synchronized (this) {
189 return exit_signal; 186 return exit_status;
190 } 187 }
191 } 188 }
192 189
193 public Integer getExitStatus() 190 public IOException getReasonClosed() {
194 { 191 synchronized (reasonClosedLock) {
195 synchronized (this) 192 return reasonClosed;
196 { 193 }
197 return exit_status; 194 }
198 } 195
199 } 196 public void setReasonClosed(IOException e) {
200 197 synchronized (reasonClosedLock) {
201 public IOException getReasonClosed()
202 {
203 synchronized (reasonClosedLock)
204 {
205 return reasonClosed;
206 }
207 }
208
209 public void setReasonClosed(IOException e)
210 {
211 synchronized (reasonClosedLock)
212 {
213 this.reasonClosed = e; 198 this.reasonClosed = e;
214 } 199 }
215 } 200 }
216 201
217 public int getState() 202 public int getState() {
218 { 203 return this.state;
219 return this.state; 204 }
220 }
221 } 205 }