comparison app/src/main/java/ch/ethz/ssh2/channel/Channel.java @ 438:d29cce60f393

migrate from Eclipse to Android Studio
author Carl Byington <carl@five-ten-sg.com>
date Thu, 03 Dec 2015 11:23:55 -0800
parents src/ch/ethz/ssh2/channel/Channel.java@071eccdff8ea
children
comparison
equal deleted inserted replaced
437:208b31032318 438:d29cce60f393
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 * 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 */
44
45 public static final int STATE_OPENING = 1;
46 public static final int STATE_OPEN = 2;
47 public static final int STATE_CLOSED = 4;
48
49 static final int CHANNEL_BUFFER_SIZE = 32 * 1024 * 3 * 2;
50
51 /*
52 * To achieve correctness, the following rules have to be respected when
53 * accessing this object:
54 */
55
56 // These fields can always be read
57 final ChannelManager cm;
58 final ChannelOutputStream stdinStream;
59 final ChannelInputStream stdoutStream;
60 final ChannelInputStream stderrStream;
61
62 // In case this channel belongs to a server-side session.
63 ServerSessionImpl ss;
64
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;
76
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 */
90
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 */
99
100 final Object channelSendLock = new Object();
101 boolean closeMessageSent = false;
102
103 /*
104 * Stop memory fragmentation by allocating this often used buffer.
105 * May only be used while holding the channelSendLock
106 */
107
108 final byte[] msgWindowAdjust = new byte[9];
109
110 // If you access (read or write) any of the following fields, then you have
111 // to synchronize on the channel.
112
113 int state = STATE_OPENING;
114
115 boolean closeMessageRecv = false;
116
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;
122
123 int localWindow = 0; /* locally, we use a small window, < 2^31 */
124 long remoteWindow = 0; /* long for readable 2^32 - 1 window support */
125
126 int localMaxPacketSize = -1;
127 int remoteMaxPacketSize = -1;
128
129 final byte[] stdoutBuffer = new byte[CHANNEL_BUFFER_SIZE];
130 final byte[] stderrBuffer = new byte[CHANNEL_BUFFER_SIZE];
131
132 int stdoutReadpos = 0;
133 int stdoutWritepos = 0;
134 int stderrReadpos = 0;
135 int stderrWritepos = 0;
136
137 boolean EOF = false;
138
139 Integer exit_status;
140
141 String exit_signal;
142
143 // we keep the x11 cookie so that this channel can be closed when this
144 // specific x11 forwarding gets stopped
145
146 String hexX11FakeCookie;
147
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.
151
152 private final Object reasonClosedLock = new Object();
153 private IOException reasonClosed = null;
154
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 }
163
164 /* Methods to allow access from classes outside of this package */
165
166 public ChannelInputStream getStderrStream() {
167 return stderrStream;
168 }
169
170 public ChannelOutputStream getStdinStream() {
171 return stdinStream;
172 }
173
174 public ChannelInputStream getStdoutStream() {
175 return stdoutStream;
176 }
177
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 }
189
190 public IOException getReasonClosed() {
191 synchronized (reasonClosedLock) {
192 return reasonClosed;
193 }
194 }
195
196 public void setReasonClosed(IOException e) {
197 synchronized (reasonClosedLock) {
198 this.reasonClosed = e;
199 }
200 }
201
202 public int getState() {
203 return this.state;
204 }
205 }