Mercurial > 510Connectbot
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 } |