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