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 }