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