273
|
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 */
|
307
|
17 public class Channel {
|
|
18 /*
|
|
19 * 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 *
|
|
22 * Any association between locks and variables is purely conventional.
|
|
23 * 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 * 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 * (...)
|
|
28 *
|
|
29 * 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 * 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 the value most recently assigned to that variable before the
|
|
34 * unlock operation.
|
|
35 *
|
|
36 * This, in conjunction with the mutual exclusion rules for locks, suffices
|
|
37 * to guarantee that values are correctly transmitted from one thread to
|
|
38 * another through shared variables.
|
|
39 *
|
|
40 * ====> Always keep that in mind when modifying the Channel/ChannelManger
|
|
41 * code.
|
|
42 *
|
|
43 */
|
273
|
44
|
307
|
45 public static final int STATE_OPENING = 1;
|
|
46 public static final int STATE_OPEN = 2;
|
|
47 public static final int STATE_CLOSED = 4;
|
273
|
48
|
307
|
49 static final int CHANNEL_BUFFER_SIZE = 32 * 1024 * 3 * 2;
|
273
|
50
|
307
|
51 /*
|
|
52 * To achieve correctness, the following rules have to be respected when
|
|
53 * accessing this object:
|
|
54 */
|
273
|
55
|
307
|
56 // These fields can always be read
|
|
57 final ChannelManager cm;
|
|
58 final ChannelOutputStream stdinStream;
|
|
59 final ChannelInputStream stdoutStream;
|
|
60 final ChannelInputStream stderrStream;
|
273
|
61
|
307
|
62 // In case this channel belongs to a server-side session.
|
|
63 ServerSessionImpl ss;
|
273
|
64
|
307
|
65 // These two fields will only be written while the Channel is in state
|
|
66 // STATE_OPENING.
|
|
67 // The code makes sure that the two fields are written out when the state is
|
|
68 // changing to STATE_OPEN.
|
|
69 // 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 // 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
|
|
74 int localID = -1;
|
|
75 int remoteID = -1;
|
273
|
76
|
307
|
77 /*
|
|
78 * Make sure that we never send a data/EOF/WindowChange msg after a CLOSE
|
|
79 * msg.
|
|
80 *
|
|
81 * 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 * 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 * 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 * implementation on the other side. But we cannot make any assumptions, we
|
|
88 * have to assume the worst case. Confused? Just believe me.
|
|
89 */
|
273
|
90
|
307
|
91 /*
|
|
92 * If you send a message on a channel, then you have to aquire the
|
|
93 * "channelSendLock" and check the "closeMessageSent" flag (this variable
|
|
94 * may only be accessed while holding the "channelSendLock" !!!
|
|
95 *
|
|
96 * BTW: NEVER EVER SEND MESSAGES FROM THE RECEIVE THREAD - see explanation
|
|
97 * above.
|
|
98 */
|
273
|
99
|
307
|
100 final Object channelSendLock = new Object();
|
|
101 boolean closeMessageSent = false;
|
273
|
102
|
307
|
103 /*
|
|
104 * Stop memory fragmentation by allocating this often used buffer.
|
|
105 * May only be used while holding the channelSendLock
|
|
106 */
|
273
|
107
|
307
|
108 final byte[] msgWindowAdjust = new byte[9];
|
273
|
109
|
307
|
110 // If you access (read or write) any of the following fields, then you have
|
|
111 // to synchronize on the channel.
|
273
|
112
|
307
|
113 int state = STATE_OPENING;
|
273
|
114
|
307
|
115 boolean closeMessageRecv = false;
|
273
|
116
|
307
|
117 /* This is a stupid implementation. At the moment we can only wait
|
|
118 * for one pending request per channel.
|
|
119 */
|
|
120 int successCounter = 0;
|
|
121 int failedCounter = 0;
|
273
|
122
|
307
|
123 int localWindow = 0; /* locally, we use a small window, < 2^31 */
|
|
124 long remoteWindow = 0; /* long for readable 2^32 - 1 window support */
|
273
|
125
|
307
|
126 int localMaxPacketSize = -1;
|
|
127 int remoteMaxPacketSize = -1;
|
273
|
128
|
307
|
129 final byte[] stdoutBuffer = new byte[CHANNEL_BUFFER_SIZE];
|
|
130 final byte[] stderrBuffer = new byte[CHANNEL_BUFFER_SIZE];
|
273
|
131
|
307
|
132 int stdoutReadpos = 0;
|
|
133 int stdoutWritepos = 0;
|
|
134 int stderrReadpos = 0;
|
|
135 int stderrWritepos = 0;
|
273
|
136
|
307
|
137 boolean EOF = false;
|
273
|
138
|
307
|
139 Integer exit_status;
|
|
140
|
|
141 String exit_signal;
|
273
|
142
|
307
|
143 // we keep the x11 cookie so that this channel can be closed when this
|
|
144 // specific x11 forwarding gets stopped
|
273
|
145
|
307
|
146 String hexX11FakeCookie;
|
273
|
147
|
307
|
148 // reasonClosed is special, since we sometimes need to access it
|
|
149 // while holding the channelSendLock.
|
|
150 // We protect it with a private short term lock.
|
273
|
151
|
307
|
152 private final Object reasonClosedLock = new Object();
|
|
153 private IOException reasonClosed = null;
|
273
|
154
|
307
|
155 public Channel(ChannelManager cm) {
|
|
156 this.cm = cm;
|
|
157 this.localWindow = CHANNEL_BUFFER_SIZE;
|
|
158 this.localMaxPacketSize = TransportManager.MAX_PACKET_SIZE;
|
|
159 this.stdinStream = new ChannelOutputStream(this);
|
|
160 this.stdoutStream = new ChannelInputStream(this, false);
|
|
161 this.stderrStream = new ChannelInputStream(this, true);
|
|
162 }
|
273
|
163
|
307
|
164 /* Methods to allow access from classes outside of this package */
|
273
|
165
|
307
|
166 public ChannelInputStream getStderrStream() {
|
|
167 return stderrStream;
|
|
168 }
|
273
|
169
|
307
|
170 public ChannelOutputStream getStdinStream() {
|
|
171 return stdinStream;
|
|
172 }
|
|
173
|
|
174 public ChannelInputStream getStdoutStream() {
|
|
175 return stdoutStream;
|
|
176 }
|
273
|
177
|
307
|
178 public String getExitSignal() {
|
|
179 synchronized (this) {
|
|
180 return exit_signal;
|
|
181 }
|
|
182 }
|
|
183
|
|
184 public Integer getExitStatus() {
|
|
185 synchronized (this) {
|
|
186 return exit_status;
|
|
187 }
|
|
188 }
|
273
|
189
|
307
|
190 public IOException getReasonClosed() {
|
|
191 synchronized (reasonClosedLock) {
|
|
192 return reasonClosed;
|
|
193 }
|
|
194 }
|
273
|
195
|
307
|
196 public void setReasonClosed(IOException e) {
|
|
197 synchronized (reasonClosedLock) {
|
273
|
198 this.reasonClosed = e;
|
307
|
199 }
|
|
200 }
|
273
|
201
|
307
|
202 public int getState() {
|
|
203 return this.state;
|
|
204 }
|
273
|
205 }
|