Mercurial > 510Connectbot
comparison src/ch/ethz/ssh2/channel/ChannelManager.java @ 308:42b15aaa7ac7 ganymed
merge
author | Carl Byington <carl@five-ten-sg.com> |
---|---|
date | Wed, 30 Jul 2014 14:21:50 -0700 |
parents | 071eccdff8ea |
children | f6d26c5f878e |
comparison
equal
deleted
inserted
replaced
306:90e47d99ea54 | 308:42b15aaa7ac7 |
---|---|
93 this.tm = state.tm; | 93 this.tm = state.tm; |
94 tm.registerMessageHandler(this, 80, 100); | 94 tm.registerMessageHandler(this, 80, 100); |
95 } | 95 } |
96 | 96 |
97 private Channel getChannel(int id) { | 97 private Channel getChannel(int id) { |
98 synchronized(channels) { | 98 synchronized (channels) { |
99 for(Channel c : channels) { | 99 for (Channel c : channels) { |
100 if(c.localID == id) { | 100 if (c.localID == id) { |
101 return c; | 101 return c; |
102 } | 102 } |
103 } | 103 } |
104 } | 104 } |
105 | |
105 return null; | 106 return null; |
106 } | 107 } |
107 | 108 |
108 private void removeChannel(int id) { | 109 private void removeChannel(int id) { |
109 synchronized(channels) { | 110 synchronized (channels) { |
110 for(Channel c : channels) { | 111 for (Channel c : channels) { |
111 if(c.localID == id) { | 112 if (c.localID == id) { |
112 channels.remove(c); | 113 channels.remove(c); |
113 break; | 114 break; |
114 } | 115 } |
115 } | 116 } |
116 } | 117 } |
117 } | 118 } |
118 | 119 |
119 private int addChannel(Channel c) { | 120 private int addChannel(Channel c) { |
120 synchronized(channels) { | 121 synchronized (channels) { |
121 channels.add(c); | 122 channels.add(c); |
122 return nextLocalChannel++; | 123 return nextLocalChannel++; |
123 } | 124 } |
124 } | 125 } |
125 | 126 |
126 private void waitUntilChannelOpen(Channel c) throws IOException { | 127 private void waitUntilChannelOpen(Channel c) throws IOException { |
127 synchronized(c) { | 128 synchronized (c) { |
128 while(c.state == Channel.STATE_OPENING) { | 129 while (c.state == Channel.STATE_OPENING) { |
129 try { | 130 try { |
130 c.wait(); | 131 c.wait(); |
131 } | 132 } |
132 catch(InterruptedException e) { | 133 catch (InterruptedException e) { |
133 throw new InterruptedIOException(e.getMessage()); | 134 throw new InterruptedIOException(e.getMessage()); |
134 } | 135 } |
135 } | 136 } |
136 | 137 |
137 if(c.state != Channel.STATE_OPEN) { | 138 if (c.state != Channel.STATE_OPEN) { |
138 removeChannel(c.localID); | 139 removeChannel(c.localID); |
139 throw c.getReasonClosed(); | 140 throw c.getReasonClosed(); |
140 } | 141 } |
141 } | 142 } |
142 } | 143 } |
143 | 144 |
144 private void waitForGlobalSuccessOrFailure() throws IOException { | 145 private void waitForGlobalSuccessOrFailure() throws IOException { |
145 synchronized(channels) { | 146 synchronized (channels) { |
146 while((globalSuccessCounter == 0) && (globalFailedCounter == 0)) { | 147 while ((globalSuccessCounter == 0) && (globalFailedCounter == 0)) { |
147 if(shutdown) { | 148 if (shutdown) { |
148 throw new IOException("The connection is being shutdown"); | 149 throw new IOException("The connection is being shutdown"); |
149 } | 150 } |
150 | 151 |
151 try { | 152 try { |
152 channels.wait(); | 153 channels.wait(); |
153 } | 154 } |
154 catch(InterruptedException e) { | 155 catch (InterruptedException e) { |
155 throw new InterruptedIOException(e.getMessage()); | 156 throw new InterruptedIOException(e.getMessage()); |
156 } | 157 } |
157 } | 158 } |
158 if((globalFailedCounter == 0) && (globalSuccessCounter == 1)) { | 159 |
160 if ((globalFailedCounter == 0) && (globalSuccessCounter == 1)) { | |
159 return; | 161 return; |
160 } | 162 } |
161 if((globalFailedCounter == 1) && (globalSuccessCounter == 0)) { | 163 |
164 if ((globalFailedCounter == 1) && (globalSuccessCounter == 0)) { | |
162 throw new IOException("The server denied the request (did you enable port forwarding?)"); | 165 throw new IOException("The server denied the request (did you enable port forwarding?)"); |
163 } | 166 } |
167 | |
164 throw new IOException("Illegal state. The server sent " + globalSuccessCounter | 168 throw new IOException("Illegal state. The server sent " + globalSuccessCounter |
165 + " SSH_MSG_REQUEST_SUCCESS and " + globalFailedCounter + " SSH_MSG_REQUEST_FAILURE messages."); | 169 + " SSH_MSG_REQUEST_SUCCESS and " + globalFailedCounter + " SSH_MSG_REQUEST_FAILURE messages."); |
166 } | 170 } |
167 } | 171 } |
168 | 172 |
169 private void waitForChannelSuccessOrFailure(Channel c) throws IOException { | 173 private void waitForChannelSuccessOrFailure(Channel c) throws IOException { |
170 synchronized(c) { | 174 synchronized (c) { |
171 while((c.successCounter == 0) && (c.failedCounter == 0)) { | 175 while ((c.successCounter == 0) && (c.failedCounter == 0)) { |
172 if(c.state != Channel.STATE_OPEN) { | 176 if (c.state != Channel.STATE_OPEN) { |
173 throw c.getReasonClosed(); | 177 throw c.getReasonClosed(); |
174 } | 178 } |
179 | |
175 try { | 180 try { |
176 c.wait(); | 181 c.wait(); |
177 } | 182 } |
178 catch(InterruptedException ignore) { | 183 catch (InterruptedException ignore) { |
179 throw new InterruptedIOException(); | 184 throw new InterruptedIOException(); |
180 } | 185 } |
181 } | 186 } |
182 if((c.failedCounter == 0) && (c.successCounter == 1)) { | 187 |
188 if ((c.failedCounter == 0) && (c.successCounter == 1)) { | |
183 return; | 189 return; |
184 } | 190 } |
185 if((c.failedCounter == 1) && (c.successCounter == 0)) { | 191 |
192 if ((c.failedCounter == 1) && (c.successCounter == 0)) { | |
186 throw new IOException("The server denied the request."); | 193 throw new IOException("The server denied the request."); |
187 } | 194 } |
195 | |
188 throw new IOException("Illegal state. The server sent " + c.successCounter | 196 throw new IOException("Illegal state. The server sent " + c.successCounter |
189 + " SSH_MSG_CHANNEL_SUCCESS and " + c.failedCounter + " SSH_MSG_CHANNEL_FAILURE messages."); | 197 + " SSH_MSG_CHANNEL_SUCCESS and " + c.failedCounter + " SSH_MSG_CHANNEL_FAILURE messages."); |
190 } | 198 } |
191 } | 199 } |
192 | 200 |
193 public void registerX11Cookie(String hexFakeCookie, X11ServerData data) { | 201 public void registerX11Cookie(String hexFakeCookie, X11ServerData data) { |
194 synchronized(x11_magic_cookies) { | 202 synchronized (x11_magic_cookies) { |
195 x11_magic_cookies.put(hexFakeCookie, data); | 203 x11_magic_cookies.put(hexFakeCookie, data); |
196 } | 204 } |
197 } | 205 } |
198 | 206 |
199 public void unRegisterX11Cookie(String hexFakeCookie, boolean killChannels) { | 207 public void unRegisterX11Cookie(String hexFakeCookie, boolean killChannels) { |
200 if(hexFakeCookie == null) { | 208 if (hexFakeCookie == null) { |
201 throw new IllegalStateException("hexFakeCookie may not be null"); | 209 throw new IllegalStateException("hexFakeCookie may not be null"); |
202 } | 210 } |
203 | 211 |
204 synchronized(x11_magic_cookies) { | 212 synchronized (x11_magic_cookies) { |
205 x11_magic_cookies.remove(hexFakeCookie); | 213 x11_magic_cookies.remove(hexFakeCookie); |
206 } | 214 } |
207 | 215 |
208 if(killChannels == false) { | 216 if (killChannels == false) { |
209 return; | 217 return; |
210 } | 218 } |
211 | 219 |
212 log.debug("Closing all X11 channels for the given fake cookie"); | 220 log.debug("Closing all X11 channels for the given fake cookie"); |
213 | |
214 List<Channel> channel_copy = new ArrayList<Channel>(); | 221 List<Channel> channel_copy = new ArrayList<Channel>(); |
215 | 222 |
216 synchronized(channels) { | 223 synchronized (channels) { |
217 channel_copy.addAll(channels); | 224 channel_copy.addAll(channels); |
218 } | 225 } |
219 | 226 |
220 for(Channel c : channel_copy) { | 227 for (Channel c : channel_copy) { |
221 synchronized(c) { | 228 synchronized (c) { |
222 if(hexFakeCookie.equals(c.hexX11FakeCookie) == false) { | 229 if (hexFakeCookie.equals(c.hexX11FakeCookie) == false) { |
223 continue; | 230 continue; |
224 } | 231 } |
225 } | 232 } |
226 | 233 |
227 try { | 234 try { |
228 closeChannel(c, "Closing X11 channel since the corresponding session is closing", true); | 235 closeChannel(c, "Closing X11 channel since the corresponding session is closing", true); |
229 } | 236 } |
230 catch(IOException ignored) { | 237 catch (IOException ignored) { |
231 } | 238 } |
232 } | 239 } |
233 } | 240 } |
234 | 241 |
235 public X11ServerData checkX11Cookie(String hexFakeCookie) { | 242 public X11ServerData checkX11Cookie(String hexFakeCookie) { |
236 synchronized(x11_magic_cookies) { | 243 synchronized (x11_magic_cookies) { |
237 if(hexFakeCookie != null) { | 244 if (hexFakeCookie != null) { |
238 return x11_magic_cookies.get(hexFakeCookie); | 245 return x11_magic_cookies.get(hexFakeCookie); |
239 } | 246 } |
240 } | 247 } |
248 | |
241 return null; | 249 return null; |
242 } | 250 } |
243 | 251 |
244 public void closeAllChannels() { | 252 public void closeAllChannels() { |
245 log.debug("Closing all channels"); | 253 log.debug("Closing all channels"); |
246 | |
247 List<Channel> channel_copy = new ArrayList<Channel>(); | 254 List<Channel> channel_copy = new ArrayList<Channel>(); |
248 | 255 |
249 synchronized(channels) { | 256 synchronized (channels) { |
250 channel_copy.addAll(channels); | 257 channel_copy.addAll(channels); |
251 } | 258 } |
252 | 259 |
253 for(Channel c : channel_copy) { | 260 for (Channel c : channel_copy) { |
254 try { | 261 try { |
255 closeChannel(c, "Closing all channels", true); | 262 closeChannel(c, "Closing all channels", true); |
256 } | 263 } |
257 catch(IOException ignored) { | 264 catch (IOException ignored) { |
258 } | 265 } |
259 } | 266 } |
260 } | 267 } |
261 | 268 |
262 public void closeChannel(Channel c, String reason, boolean force) throws IOException { | 269 public void closeChannel(Channel c, String reason, boolean force) throws IOException { |
264 } | 271 } |
265 | 272 |
266 public void closeChannel(Channel c, IOException reason, boolean force) throws IOException { | 273 public void closeChannel(Channel c, IOException reason, boolean force) throws IOException { |
267 byte msg[] = new byte[5]; | 274 byte msg[] = new byte[5]; |
268 | 275 |
269 synchronized(c) { | 276 synchronized (c) { |
270 if(force) { | 277 if (force) { |
271 c.state = Channel.STATE_CLOSED; | 278 c.state = Channel.STATE_CLOSED; |
272 c.EOF = true; | 279 c.EOF = true; |
273 } | 280 } |
274 | 281 |
275 c.setReasonClosed(reason); | 282 c.setReasonClosed(reason); |
276 | |
277 msg[0] = Packets.SSH_MSG_CHANNEL_CLOSE; | 283 msg[0] = Packets.SSH_MSG_CHANNEL_CLOSE; |
278 msg[1] = (byte) (c.remoteID >> 24); | 284 msg[1] = (byte)(c.remoteID >> 24); |
279 msg[2] = (byte) (c.remoteID >> 16); | 285 msg[2] = (byte)(c.remoteID >> 16); |
280 msg[3] = (byte) (c.remoteID >> 8); | 286 msg[3] = (byte)(c.remoteID >> 8); |
281 msg[4] = (byte) (c.remoteID); | 287 msg[4] = (byte)(c.remoteID); |
282 | |
283 c.notifyAll(); | 288 c.notifyAll(); |
284 } | 289 } |
285 | 290 |
286 synchronized(c.channelSendLock) { | 291 synchronized (c.channelSendLock) { |
287 if(c.closeMessageSent) { | 292 if (c.closeMessageSent) { |
288 return; | 293 return; |
289 } | 294 } |
295 | |
290 tm.sendMessage(msg); | 296 tm.sendMessage(msg); |
291 c.closeMessageSent = true; | 297 c.closeMessageSent = true; |
292 } | 298 } |
293 | 299 |
294 log.debug("Sent SSH_MSG_CHANNEL_CLOSE (channel " + c.localID + ")"); | 300 log.debug("Sent SSH_MSG_CHANNEL_CLOSE (channel " + c.localID + ")"); |
295 } | 301 } |
296 | 302 |
297 public void sendEOF(Channel c) throws IOException { | 303 public void sendEOF(Channel c) throws IOException { |
298 byte[] msg = new byte[5]; | 304 byte[] msg = new byte[5]; |
299 | 305 |
300 synchronized(c) { | 306 synchronized (c) { |
301 if(c.state != Channel.STATE_OPEN) { | 307 if (c.state != Channel.STATE_OPEN) { |
302 return; | 308 return; |
303 } | 309 } |
304 | 310 |
305 msg[0] = Packets.SSH_MSG_CHANNEL_EOF; | 311 msg[0] = Packets.SSH_MSG_CHANNEL_EOF; |
306 msg[1] = (byte) (c.remoteID >> 24); | 312 msg[1] = (byte)(c.remoteID >> 24); |
307 msg[2] = (byte) (c.remoteID >> 16); | 313 msg[2] = (byte)(c.remoteID >> 16); |
308 msg[3] = (byte) (c.remoteID >> 8); | 314 msg[3] = (byte)(c.remoteID >> 8); |
309 msg[4] = (byte) (c.remoteID); | 315 msg[4] = (byte)(c.remoteID); |
310 } | 316 } |
311 | 317 |
312 synchronized(c.channelSendLock) { | 318 synchronized (c.channelSendLock) { |
313 if(c.closeMessageSent == true) { | 319 if (c.closeMessageSent == true) { |
314 return; | 320 return; |
315 } | 321 } |
322 | |
316 tm.sendMessage(msg); | 323 tm.sendMessage(msg); |
317 } | 324 } |
318 | |
319 | 325 |
320 log.debug("Sent EOF (Channel " + c.localID + "/" + c.remoteID + ")"); | 326 log.debug("Sent EOF (Channel " + c.localID + "/" + c.remoteID + ")"); |
321 } | 327 } |
322 | 328 |
323 public void sendOpenConfirmation(Channel c) throws IOException { | 329 public void sendOpenConfirmation(Channel c) throws IOException { |
324 PacketChannelOpenConfirmation pcoc = null; | 330 PacketChannelOpenConfirmation pcoc = null; |
325 | 331 |
326 synchronized(c) { | 332 synchronized (c) { |
327 if(c.state != Channel.STATE_OPENING) { | 333 if (c.state != Channel.STATE_OPENING) { |
328 return; | 334 return; |
329 } | 335 } |
330 | 336 |
331 c.state = Channel.STATE_OPEN; | 337 c.state = Channel.STATE_OPEN; |
332 | |
333 pcoc = new PacketChannelOpenConfirmation(c.remoteID, c.localID, c.localWindow, c.localMaxPacketSize); | 338 pcoc = new PacketChannelOpenConfirmation(c.remoteID, c.localID, c.localWindow, c.localMaxPacketSize); |
334 } | 339 } |
335 | 340 |
336 synchronized(c.channelSendLock) { | 341 synchronized (c.channelSendLock) { |
337 if(c.closeMessageSent == true) { | 342 if (c.closeMessageSent == true) { |
338 return; | 343 return; |
339 } | 344 } |
345 | |
340 tm.sendMessage(pcoc.getPayload()); | 346 tm.sendMessage(pcoc.getPayload()); |
341 } | 347 } |
342 } | 348 } |
343 | 349 |
344 public void sendData(Channel c, byte[] buffer, int pos, int len) throws IOException { | 350 public void sendData(Channel c, byte[] buffer, int pos, int len) throws IOException { |
345 while(len > 0) { | 351 while (len > 0) { |
346 int thislen = 0; | 352 int thislen = 0; |
347 byte[] msg; | 353 byte[] msg; |
348 | 354 |
349 synchronized(c) { | 355 synchronized (c) { |
350 while(true) { | 356 while (true) { |
351 if(c.state == Channel.STATE_CLOSED) { | 357 if (c.state == Channel.STATE_CLOSED) { |
352 throw c.getReasonClosed(); | 358 throw c.getReasonClosed(); |
353 } | 359 } |
354 if(c.state != Channel.STATE_OPEN) { | 360 |
361 if (c.state != Channel.STATE_OPEN) { | |
355 throw new ChannelClosedException("SSH channel in strange state. (" + c.state + ")"); | 362 throw new ChannelClosedException("SSH channel in strange state. (" + c.state + ")"); |
356 } | 363 } |
357 | 364 |
358 if(c.remoteWindow != 0) { | 365 if (c.remoteWindow != 0) { |
359 break; | 366 break; |
360 } | 367 } |
361 | 368 |
362 try { | 369 try { |
363 c.wait(); | 370 c.wait(); |
364 } | 371 } |
365 catch(InterruptedException e) { | 372 catch (InterruptedException e) { |
366 throw new InterruptedIOException(e.getMessage()); | 373 throw new InterruptedIOException(e.getMessage()); |
367 } | 374 } |
368 } | 375 } |
369 | 376 |
370 /* len > 0, no sign extension can happen when comparing */ | 377 /* len > 0, no sign extension can happen when comparing */ |
371 | |
372 thislen = (c.remoteWindow >= len) ? len : (int) c.remoteWindow; | 378 thislen = (c.remoteWindow >= len) ? len : (int) c.remoteWindow; |
373 | |
374 int estimatedMaxDataLen = c.remoteMaxPacketSize - (tm.getPacketOverheadEstimate() + 9); | 379 int estimatedMaxDataLen = c.remoteMaxPacketSize - (tm.getPacketOverheadEstimate() + 9); |
375 | 380 |
376 /* The worst case scenario =) a true bottleneck */ | 381 /* The worst case scenario =) a true bottleneck */ |
377 | 382 |
378 if(estimatedMaxDataLen <= 0) { | 383 if (estimatedMaxDataLen <= 0) { |
379 estimatedMaxDataLen = 1; | 384 estimatedMaxDataLen = 1; |
380 } | 385 } |
381 | 386 |
382 if(thislen > estimatedMaxDataLen) { | 387 if (thislen > estimatedMaxDataLen) { |
383 thislen = estimatedMaxDataLen; | 388 thislen = estimatedMaxDataLen; |
384 } | 389 } |
385 | 390 |
386 c.remoteWindow -= thislen; | 391 c.remoteWindow -= thislen; |
387 | |
388 msg = new byte[1 + 8 + thislen]; | 392 msg = new byte[1 + 8 + thislen]; |
389 | |
390 msg[0] = Packets.SSH_MSG_CHANNEL_DATA; | 393 msg[0] = Packets.SSH_MSG_CHANNEL_DATA; |
391 msg[1] = (byte) (c.remoteID >> 24); | 394 msg[1] = (byte)(c.remoteID >> 24); |
392 msg[2] = (byte) (c.remoteID >> 16); | 395 msg[2] = (byte)(c.remoteID >> 16); |
393 msg[3] = (byte) (c.remoteID >> 8); | 396 msg[3] = (byte)(c.remoteID >> 8); |
394 msg[4] = (byte) (c.remoteID); | 397 msg[4] = (byte)(c.remoteID); |
395 msg[5] = (byte) (thislen >> 24); | 398 msg[5] = (byte)(thislen >> 24); |
396 msg[6] = (byte) (thislen >> 16); | 399 msg[6] = (byte)(thislen >> 16); |
397 msg[7] = (byte) (thislen >> 8); | 400 msg[7] = (byte)(thislen >> 8); |
398 msg[8] = (byte) (thislen); | 401 msg[8] = (byte)(thislen); |
399 | |
400 System.arraycopy(buffer, pos, msg, 9, thislen); | 402 System.arraycopy(buffer, pos, msg, 9, thislen); |
401 } | 403 } |
402 | 404 |
403 synchronized(c.channelSendLock) { | 405 synchronized (c.channelSendLock) { |
404 if(c.closeMessageSent) { | 406 if (c.closeMessageSent) { |
405 throw c.getReasonClosed(); | 407 throw c.getReasonClosed(); |
406 } | 408 } |
409 | |
407 tm.sendMessage(msg); | 410 tm.sendMessage(msg); |
408 } | 411 } |
409 | 412 |
410 pos += thislen; | 413 pos += thislen; |
411 len -= thislen; | 414 len -= thislen; |
412 } | 415 } |
413 } | 416 } |
414 | 417 |
415 public int requestGlobalForward(String bindAddress, int bindPort, String targetAddress, int targetPort) | 418 public int requestGlobalForward(String bindAddress, int bindPort, String targetAddress, int targetPort) |
416 throws IOException { | 419 throws IOException { |
417 RemoteForwardingData rfd = new RemoteForwardingData(); | 420 RemoteForwardingData rfd = new RemoteForwardingData(); |
418 | |
419 rfd.bindAddress = bindAddress; | 421 rfd.bindAddress = bindAddress; |
420 rfd.bindPort = bindPort; | 422 rfd.bindPort = bindPort; |
421 rfd.targetAddress = targetAddress; | 423 rfd.targetAddress = targetAddress; |
422 rfd.targetPort = targetPort; | 424 rfd.targetPort = targetPort; |
423 | 425 |
424 synchronized(remoteForwardings) { | 426 synchronized (remoteForwardings) { |
425 if(remoteForwardings.get(bindPort) != null) { | 427 if (remoteForwardings.get(bindPort) != null) { |
426 throw new IOException("There is already a forwarding for remote port " + bindPort); | 428 throw new IOException("There is already a forwarding for remote port " + bindPort); |
427 } | 429 } |
430 | |
428 remoteForwardings.put(bindPort, rfd); | 431 remoteForwardings.put(bindPort, rfd); |
429 } | 432 } |
430 | 433 |
431 synchronized(channels) { | 434 synchronized (channels) { |
432 globalSuccessCounter = globalFailedCounter = 0; | 435 globalSuccessCounter = globalFailedCounter = 0; |
433 } | 436 } |
434 | 437 |
435 PacketGlobalForwardRequest pgf = new PacketGlobalForwardRequest(true, bindAddress, bindPort); | 438 PacketGlobalForwardRequest pgf = new PacketGlobalForwardRequest(true, bindAddress, bindPort); |
436 tm.sendMessage(pgf.getPayload()); | 439 tm.sendMessage(pgf.getPayload()); |
437 | |
438 log.debug("Requesting a remote forwarding ('" + bindAddress + "', " + bindPort + ")"); | 440 log.debug("Requesting a remote forwarding ('" + bindAddress + "', " + bindPort + ")"); |
439 | 441 |
440 try { | 442 try { |
441 waitForGlobalSuccessOrFailure(); | 443 waitForGlobalSuccessOrFailure(); |
442 } | 444 } |
443 catch(IOException e) { | 445 catch (IOException e) { |
444 synchronized(remoteForwardings) { | 446 synchronized (remoteForwardings) { |
445 remoteForwardings.remove(bindPort); | 447 remoteForwardings.remove(bindPort); |
446 } | 448 } |
449 | |
447 throw e; | 450 throw e; |
448 } | 451 } |
449 | 452 |
450 return bindPort; | 453 return bindPort; |
451 } | 454 } |
452 | 455 |
453 public void requestCancelGlobalForward(int bindPort) throws IOException { | 456 public void requestCancelGlobalForward(int bindPort) throws IOException { |
454 RemoteForwardingData rfd; | 457 RemoteForwardingData rfd; |
455 | 458 |
456 synchronized(remoteForwardings) { | 459 synchronized (remoteForwardings) { |
457 rfd = remoteForwardings.get(bindPort); | 460 rfd = remoteForwardings.get(bindPort); |
458 | 461 |
459 if(rfd == null) { | 462 if (rfd == null) { |
460 throw new IOException("Sorry, there is no known remote forwarding for remote port " + bindPort); | 463 throw new IOException("Sorry, there is no known remote forwarding for remote port " + bindPort); |
461 } | 464 } |
462 } | 465 } |
463 | 466 |
464 synchronized(channels) { | 467 synchronized (channels) { |
465 globalSuccessCounter = globalFailedCounter = 0; | 468 globalSuccessCounter = globalFailedCounter = 0; |
466 } | 469 } |
467 | 470 |
468 PacketGlobalCancelForwardRequest pgcf = new PacketGlobalCancelForwardRequest(true, rfd.bindAddress, | 471 PacketGlobalCancelForwardRequest pgcf = new PacketGlobalCancelForwardRequest(true, rfd.bindAddress, |
469 rfd.bindPort); | 472 rfd.bindPort); |
470 tm.sendMessage(pgcf.getPayload()); | 473 tm.sendMessage(pgcf.getPayload()); |
471 | |
472 log.debug("Requesting cancelation of remote forward ('" + rfd.bindAddress + "', " + rfd.bindPort + ")"); | 474 log.debug("Requesting cancelation of remote forward ('" + rfd.bindAddress + "', " + rfd.bindPort + ")"); |
473 | |
474 waitForGlobalSuccessOrFailure(); | 475 waitForGlobalSuccessOrFailure(); |
475 | 476 |
476 /* Only now we are sure that no more forwarded connections will arrive */ | 477 /* Only now we are sure that no more forwarded connections will arrive */ |
477 | 478 |
478 synchronized(remoteForwardings) { | 479 synchronized (remoteForwardings) { |
479 remoteForwardings.remove(bindPort); | 480 remoteForwardings.remove(bindPort); |
480 } | 481 } |
481 } | 482 } |
482 | 483 |
483 /** | 484 /** |
495 synchronized (channels) { | 496 synchronized (channels) { |
496 globalSuccessCounter = globalFailedCounter = 0; | 497 globalSuccessCounter = globalFailedCounter = 0; |
497 } | 498 } |
498 | 499 |
499 log.debug("Requesting agent forwarding"); | 500 log.debug("Requesting agent forwarding"); |
500 | |
501 PacketChannelAuthAgentReq aar = new PacketChannelAuthAgentReq(c.remoteID); | 501 PacketChannelAuthAgentReq aar = new PacketChannelAuthAgentReq(c.remoteID); |
502 synchronized(c.channelSendLock) { | 502 |
503 synchronized (c.channelSendLock) { | |
503 if (c.closeMessageSent) { | 504 if (c.closeMessageSent) { |
504 throw c.getReasonClosed(); | 505 throw c.getReasonClosed(); |
505 } | 506 } |
507 | |
506 tm.sendMessage(aar.getPayload()); | 508 tm.sendMessage(aar.getPayload()); |
507 } | 509 } |
508 | 510 |
509 try { | 511 try { |
510 waitForChannelSuccessOrFailure(c); | 512 waitForChannelSuccessOrFailure(c); |
511 } | 513 } |
512 catch(IOException e) { | 514 catch (IOException e) { |
513 authAgent = null; | 515 authAgent = null; |
514 throw e; | 516 throw e; |
515 } | 517 } |
516 } | 518 } |
517 | 519 |
518 public void registerThread(IChannelWorkerThread thr) throws IOException { | 520 public void registerThread(IChannelWorkerThread thr) throws IOException { |
519 synchronized(listenerThreads) { | 521 synchronized (listenerThreads) { |
520 if(listenerThreadsAllowed == false) { | 522 if (listenerThreadsAllowed == false) { |
521 throw new IOException("Too late, this connection is closed."); | 523 throw new IOException("Too late, this connection is closed."); |
522 } | 524 } |
525 | |
523 listenerThreads.add(thr); | 526 listenerThreads.add(thr); |
524 } | 527 } |
525 } | 528 } |
526 | 529 |
527 public Channel openDirectTCPIPChannel(String host_to_connect, int port_to_connect, String originator_IP_address, | 530 public Channel openDirectTCPIPChannel(String host_to_connect, int port_to_connect, String originator_IP_address, |
528 int originator_port) throws IOException { | 531 int originator_port) throws IOException { |
529 Channel c = new Channel(this); | 532 Channel c = new Channel(this); |
530 | 533 |
531 synchronized(c) { | 534 synchronized (c) { |
532 c.localID = addChannel(c); | 535 c.localID = addChannel(c); |
533 // end of synchronized block forces writing out to main memory | 536 // end of synchronized block forces writing out to main memory |
534 } | 537 } |
535 | 538 |
536 PacketOpenDirectTCPIPChannel dtc = new PacketOpenDirectTCPIPChannel(c.localID, c.localWindow, | 539 PacketOpenDirectTCPIPChannel dtc = new PacketOpenDirectTCPIPChannel(c.localID, c.localWindow, |
537 c.localMaxPacketSize, host_to_connect, port_to_connect, originator_IP_address, originator_port); | 540 c.localMaxPacketSize, host_to_connect, port_to_connect, originator_IP_address, originator_port); |
538 | |
539 tm.sendMessage(dtc.getPayload()); | 541 tm.sendMessage(dtc.getPayload()); |
540 | |
541 waitUntilChannelOpen(c); | 542 waitUntilChannelOpen(c); |
542 | |
543 return c; | 543 return c; |
544 } | 544 } |
545 | 545 |
546 public Channel openSessionChannel() throws IOException { | 546 public Channel openSessionChannel() throws IOException { |
547 Channel c = new Channel(this); | 547 Channel c = new Channel(this); |
548 | 548 |
549 synchronized(c) { | 549 synchronized (c) { |
550 c.localID = addChannel(c); | 550 c.localID = addChannel(c); |
551 // end of synchronized block forces the writing out to main memory | 551 // end of synchronized block forces the writing out to main memory |
552 } | 552 } |
553 | 553 |
554 log.debug("Sending SSH_MSG_CHANNEL_OPEN (Channel " + c.localID + ")"); | 554 log.debug("Sending SSH_MSG_CHANNEL_OPEN (Channel " + c.localID + ")"); |
555 | |
556 PacketOpenSessionChannel smo = new PacketOpenSessionChannel(c.localID, c.localWindow, c.localMaxPacketSize); | 555 PacketOpenSessionChannel smo = new PacketOpenSessionChannel(c.localID, c.localWindow, c.localMaxPacketSize); |
557 tm.sendMessage(smo.getPayload()); | 556 tm.sendMessage(smo.getPayload()); |
558 | |
559 waitUntilChannelOpen(c); | 557 waitUntilChannelOpen(c); |
560 | |
561 return c; | 558 return c; |
562 } | 559 } |
563 | 560 |
564 public void requestPTY(Channel c, String term, int term_width_characters, int term_height_characters, | 561 public void requestPTY(Channel c, String term, int term_width_characters, int term_height_characters, |
565 int term_width_pixels, int term_height_pixels, byte[] terminal_modes) throws IOException { | 562 int term_width_pixels, int term_height_pixels, byte[] terminal_modes) throws IOException { |
566 PacketSessionPtyRequest spr; | 563 PacketSessionPtyRequest spr; |
567 | 564 |
568 synchronized(c) { | 565 synchronized (c) { |
569 if(c.state != Channel.STATE_OPEN) { | 566 if (c.state != Channel.STATE_OPEN) { |
570 throw c.getReasonClosed(); | 567 throw c.getReasonClosed(); |
571 } | 568 } |
569 | |
572 spr = new PacketSessionPtyRequest(c.remoteID, true, term, term_width_characters, term_height_characters, | 570 spr = new PacketSessionPtyRequest(c.remoteID, true, term, term_width_characters, term_height_characters, |
573 term_width_pixels, term_height_pixels, terminal_modes); | 571 term_width_pixels, term_height_pixels, terminal_modes); |
574 | |
575 c.successCounter = c.failedCounter = 0; | 572 c.successCounter = c.failedCounter = 0; |
576 } | 573 } |
577 | 574 |
578 synchronized(c.channelSendLock) { | 575 synchronized (c.channelSendLock) { |
579 if(c.closeMessageSent) { | 576 if (c.closeMessageSent) { |
580 throw c.getReasonClosed(); | 577 throw c.getReasonClosed(); |
581 } | 578 } |
579 | |
582 tm.sendMessage(spr.getPayload()); | 580 tm.sendMessage(spr.getPayload()); |
583 } | 581 } |
584 | 582 |
585 try { | 583 try { |
586 waitForChannelSuccessOrFailure(c); | 584 waitForChannelSuccessOrFailure(c); |
587 } | 585 } |
588 catch(IOException e) { | 586 catch (IOException e) { |
589 throw new IOException("PTY request failed", e); | 587 throw new IOException("PTY request failed", e); |
590 } | 588 } |
591 } | 589 } |
592 | 590 |
593 public void requestWindowChange(Channel c, int term_width_characters, int term_height_characters, | 591 public void requestWindowChange(Channel c, int term_width_characters, int term_height_characters, |
594 int term_width_pixels, int term_height_pixels) throws IOException { | 592 int term_width_pixels, int term_height_pixels) throws IOException { |
595 PacketWindowChange pwc; | 593 PacketWindowChange pwc; |
596 | 594 |
597 synchronized(c) { | 595 synchronized (c) { |
598 if(c.state != Channel.STATE_OPEN) { | 596 if (c.state != Channel.STATE_OPEN) { |
599 throw c.getReasonClosed(); | 597 throw c.getReasonClosed(); |
600 } | 598 } |
599 | |
601 pwc = new PacketWindowChange(c.remoteID, term_width_characters, term_height_characters, | 600 pwc = new PacketWindowChange(c.remoteID, term_width_characters, term_height_characters, |
602 term_width_pixels, term_height_pixels); | 601 term_width_pixels, term_height_pixels); |
603 | |
604 c.successCounter = c.failedCounter = 0; | 602 c.successCounter = c.failedCounter = 0; |
605 } | 603 } |
606 | 604 |
607 synchronized(c.channelSendLock) { | 605 synchronized (c.channelSendLock) { |
608 if(c.closeMessageSent) { | 606 if (c.closeMessageSent) { |
609 throw c.getReasonClosed(); | 607 throw c.getReasonClosed(); |
610 } | 608 } |
609 | |
611 tm.sendMessage(pwc.getPayload()); | 610 tm.sendMessage(pwc.getPayload()); |
612 } | 611 } |
613 | 612 |
614 try { | 613 try { |
615 waitForChannelSuccessOrFailure(c); | 614 waitForChannelSuccessOrFailure(c); |
616 } | 615 } |
617 catch(IOException e) { | 616 catch (IOException e) { |
618 throw new IOException("The window-change request failed.", e); | 617 throw new IOException("The window-change request failed.", e); |
619 } | 618 } |
620 } | 619 } |
621 | 620 |
622 public void requestX11(Channel c, boolean singleConnection, String x11AuthenticationProtocol, | 621 public void requestX11(Channel c, boolean singleConnection, String x11AuthenticationProtocol, |
623 String x11AuthenticationCookie, int x11ScreenNumber) throws IOException { | 622 String x11AuthenticationCookie, int x11ScreenNumber) throws IOException { |
624 PacketSessionX11Request psr; | 623 PacketSessionX11Request psr; |
625 | 624 |
626 synchronized(c) { | 625 synchronized (c) { |
627 if(c.state != Channel.STATE_OPEN) { | 626 if (c.state != Channel.STATE_OPEN) { |
628 throw c.getReasonClosed(); | 627 throw c.getReasonClosed(); |
629 } | 628 } |
629 | |
630 psr = new PacketSessionX11Request(c.remoteID, true, singleConnection, x11AuthenticationProtocol, | 630 psr = new PacketSessionX11Request(c.remoteID, true, singleConnection, x11AuthenticationProtocol, |
631 x11AuthenticationCookie, x11ScreenNumber); | 631 x11AuthenticationCookie, x11ScreenNumber); |
632 | |
633 c.successCounter = c.failedCounter = 0; | 632 c.successCounter = c.failedCounter = 0; |
634 } | 633 } |
635 | 634 |
636 synchronized(c.channelSendLock) { | 635 synchronized (c.channelSendLock) { |
637 if(c.closeMessageSent) { | 636 if (c.closeMessageSent) { |
638 throw c.getReasonClosed(); | 637 throw c.getReasonClosed(); |
639 } | 638 } |
639 | |
640 tm.sendMessage(psr.getPayload()); | 640 tm.sendMessage(psr.getPayload()); |
641 } | 641 } |
642 | 642 |
643 log.debug("Requesting X11 forwarding (Channel " + c.localID + "/" + c.remoteID + ")"); | 643 log.debug("Requesting X11 forwarding (Channel " + c.localID + "/" + c.remoteID + ")"); |
644 | 644 |
645 try { | 645 try { |
646 waitForChannelSuccessOrFailure(c); | 646 waitForChannelSuccessOrFailure(c); |
647 } | 647 } |
648 catch(IOException e) { | 648 catch (IOException e) { |
649 throw new IOException("The X11 request failed.", e); | 649 throw new IOException("The X11 request failed.", e); |
650 } | 650 } |
651 } | 651 } |
652 | 652 |
653 public void requestSubSystem(Channel c, String subSystemName) throws IOException { | 653 public void requestSubSystem(Channel c, String subSystemName) throws IOException { |
654 PacketSessionSubsystemRequest ssr; | 654 PacketSessionSubsystemRequest ssr; |
655 | 655 |
656 synchronized(c) { | 656 synchronized (c) { |
657 if(c.state != Channel.STATE_OPEN) { | 657 if (c.state != Channel.STATE_OPEN) { |
658 throw c.getReasonClosed(); | 658 throw c.getReasonClosed(); |
659 } | 659 } |
660 | |
660 ssr = new PacketSessionSubsystemRequest(c.remoteID, true, subSystemName); | 661 ssr = new PacketSessionSubsystemRequest(c.remoteID, true, subSystemName); |
661 | |
662 c.successCounter = c.failedCounter = 0; | 662 c.successCounter = c.failedCounter = 0; |
663 } | 663 } |
664 | 664 |
665 synchronized(c.channelSendLock) { | 665 synchronized (c.channelSendLock) { |
666 if(c.closeMessageSent) { | 666 if (c.closeMessageSent) { |
667 throw c.getReasonClosed(); | 667 throw c.getReasonClosed(); |
668 } | 668 } |
669 | |
669 tm.sendMessage(ssr.getPayload()); | 670 tm.sendMessage(ssr.getPayload()); |
670 } | 671 } |
671 | 672 |
672 try { | 673 try { |
673 waitForChannelSuccessOrFailure(c); | 674 waitForChannelSuccessOrFailure(c); |
674 } | 675 } |
675 catch(IOException e) { | 676 catch (IOException e) { |
676 throw new IOException("The subsystem request failed.", e); | 677 throw new IOException("The subsystem request failed.", e); |
677 } | 678 } |
678 } | 679 } |
679 | 680 |
680 public void requestExecCommand(Channel c, String cmd) throws IOException { | 681 public void requestExecCommand(Channel c, String cmd) throws IOException { |
685 * @param charsetName The charset used to convert between Java Unicode Strings and byte encodings | 686 * @param charsetName The charset used to convert between Java Unicode Strings and byte encodings |
686 */ | 687 */ |
687 public void requestExecCommand(Channel c, String cmd, String charsetName) throws IOException { | 688 public void requestExecCommand(Channel c, String cmd, String charsetName) throws IOException { |
688 PacketSessionExecCommand sm; | 689 PacketSessionExecCommand sm; |
689 | 690 |
690 synchronized(c) { | 691 synchronized (c) { |
691 if(c.state != Channel.STATE_OPEN) { | 692 if (c.state != Channel.STATE_OPEN) { |
692 throw c.getReasonClosed(); | 693 throw c.getReasonClosed(); |
693 } | 694 } |
695 | |
694 sm = new PacketSessionExecCommand(c.remoteID, true, cmd, charsetName); | 696 sm = new PacketSessionExecCommand(c.remoteID, true, cmd, charsetName); |
695 | |
696 c.successCounter = c.failedCounter = 0; | 697 c.successCounter = c.failedCounter = 0; |
697 } | 698 } |
698 | 699 |
699 synchronized(c.channelSendLock) { | 700 synchronized (c.channelSendLock) { |
700 if(c.closeMessageSent) { | 701 if (c.closeMessageSent) { |
701 throw c.getReasonClosed(); | 702 throw c.getReasonClosed(); |
702 } | 703 } |
704 | |
703 tm.sendMessage(sm.getPayload()); | 705 tm.sendMessage(sm.getPayload()); |
704 } | 706 } |
705 | 707 |
706 log.debug("Executing command (channel " + c.localID + ", '" + cmd + "')"); | 708 log.debug("Executing command (channel " + c.localID + ", '" + cmd + "')"); |
707 | 709 |
708 try { | 710 try { |
709 waitForChannelSuccessOrFailure(c); | 711 waitForChannelSuccessOrFailure(c); |
710 } | 712 } |
711 catch(IOException e) { | 713 catch (IOException e) { |
712 throw new IOException("The execute request failed.", e); | 714 throw new IOException("The execute request failed.", e); |
713 } | 715 } |
714 } | 716 } |
715 | 717 |
716 public void requestShell(Channel c) throws IOException { | 718 public void requestShell(Channel c) throws IOException { |
717 PacketSessionStartShell sm; | 719 PacketSessionStartShell sm; |
718 | 720 |
719 synchronized(c) { | 721 synchronized (c) { |
720 if(c.state != Channel.STATE_OPEN) { | 722 if (c.state != Channel.STATE_OPEN) { |
721 throw c.getReasonClosed(); | 723 throw c.getReasonClosed(); |
722 } | 724 } |
725 | |
723 sm = new PacketSessionStartShell(c.remoteID, true); | 726 sm = new PacketSessionStartShell(c.remoteID, true); |
724 | |
725 c.successCounter = c.failedCounter = 0; | 727 c.successCounter = c.failedCounter = 0; |
726 } | 728 } |
727 | 729 |
728 synchronized(c.channelSendLock) { | 730 synchronized (c.channelSendLock) { |
729 if(c.closeMessageSent) { | 731 if (c.closeMessageSent) { |
730 throw c.getReasonClosed(); | 732 throw c.getReasonClosed(); |
731 } | 733 } |
734 | |
732 tm.sendMessage(sm.getPayload()); | 735 tm.sendMessage(sm.getPayload()); |
733 } | 736 } |
734 | 737 |
735 try { | 738 try { |
736 waitForChannelSuccessOrFailure(c); | 739 waitForChannelSuccessOrFailure(c); |
737 } | 740 } |
738 catch(IOException e) { | 741 catch (IOException e) { |
739 throw new IOException("The shell request failed.", e); | 742 throw new IOException("The shell request failed.", e); |
740 } | 743 } |
741 } | 744 } |
742 | 745 |
743 public void msgChannelExtendedData(byte[] msg) throws IOException { | 746 public void msgChannelExtendedData(byte[] msg) throws IOException { |
744 if(msg.length <= 13) { | 747 if (msg.length <= 13) { |
745 throw new PacketFormatException(String.format("SSH_MSG_CHANNEL_EXTENDED_DATA message has wrong size (%d)", msg.length)); | 748 throw new PacketFormatException(String.format("SSH_MSG_CHANNEL_EXTENDED_DATA message has wrong size (%d)", msg.length)); |
746 } | 749 } |
747 | 750 |
748 int id = ((msg[1] & 0xff) << 24) | ((msg[2] & 0xff) << 16) | ((msg[3] & 0xff) << 8) | (msg[4] & 0xff); | 751 int id = ((msg[1] & 0xff) << 24) | ((msg[2] & 0xff) << 16) | ((msg[3] & 0xff) << 8) | (msg[4] & 0xff); |
749 int dataType = ((msg[5] & 0xff) << 24) | ((msg[6] & 0xff) << 16) | ((msg[7] & 0xff) << 8) | (msg[8] & 0xff); | 752 int dataType = ((msg[5] & 0xff) << 24) | ((msg[6] & 0xff) << 16) | ((msg[7] & 0xff) << 8) | (msg[8] & 0xff); |
750 int len = ((msg[9] & 0xff) << 24) | ((msg[10] & 0xff) << 16) | ((msg[11] & 0xff) << 8) | (msg[12] & 0xff); | 753 int len = ((msg[9] & 0xff) << 24) | ((msg[10] & 0xff) << 16) | ((msg[11] & 0xff) << 8) | (msg[12] & 0xff); |
751 | |
752 Channel c = getChannel(id); | 754 Channel c = getChannel(id); |
753 | 755 |
754 if(c == null) { | 756 if (c == null) { |
755 throw new PacketTypeException("Unexpected SSH_MSG_CHANNEL_EXTENDED_DATA message for non-existent channel " + id); | 757 throw new PacketTypeException("Unexpected SSH_MSG_CHANNEL_EXTENDED_DATA message for non-existent channel " + id); |
756 } | 758 } |
757 | 759 |
758 if(dataType != Packets.SSH_EXTENDED_DATA_STDERR) { | 760 if (dataType != Packets.SSH_EXTENDED_DATA_STDERR) { |
759 throw new PacketFormatException("SSH_MSG_CHANNEL_EXTENDED_DATA message has unknown type (" + dataType + ")"); | 761 throw new PacketFormatException("SSH_MSG_CHANNEL_EXTENDED_DATA message has unknown type (" + dataType + ")"); |
760 } | 762 } |
761 | 763 |
762 if(len != (msg.length - 13)) { | 764 if (len != (msg.length - 13)) { |
763 throw new PacketFormatException("SSH_MSG_CHANNEL_EXTENDED_DATA message has wrong len (calculated " + (msg.length - 13) | 765 throw new PacketFormatException("SSH_MSG_CHANNEL_EXTENDED_DATA message has wrong len (calculated " + (msg.length - 13) |
764 + ", got " + len + ")"); | 766 + ", got " + len + ")"); |
765 } | 767 } |
766 | 768 |
767 log.debug("Got SSH_MSG_CHANNEL_EXTENDED_DATA (channel " + id + ", " + len + ")"); | 769 log.debug("Got SSH_MSG_CHANNEL_EXTENDED_DATA (channel " + id + ", " + len + ")"); |
768 | 770 |
769 synchronized(c) { | 771 synchronized (c) { |
770 if(c.state == Channel.STATE_CLOSED) { | 772 if (c.state == Channel.STATE_CLOSED) { |
771 return; // ignore | 773 return; // ignore |
772 } | 774 } |
773 | 775 |
774 if(c.state != Channel.STATE_OPEN) { | 776 if (c.state != Channel.STATE_OPEN) { |
775 throw new PacketTypeException("Got SSH_MSG_CHANNEL_EXTENDED_DATA, but channel is not in correct state (" | 777 throw new PacketTypeException("Got SSH_MSG_CHANNEL_EXTENDED_DATA, but channel is not in correct state (" |
776 + c.state + ")"); | 778 + c.state + ")"); |
777 } | 779 } |
778 | 780 |
779 if(c.localWindow < len) { | 781 if (c.localWindow < len) { |
780 throw new PacketFormatException("Remote sent too much data, does not fit into window."); | 782 throw new PacketFormatException("Remote sent too much data, does not fit into window."); |
781 } | 783 } |
782 | 784 |
783 c.localWindow -= len; | 785 c.localWindow -= len; |
784 | |
785 System.arraycopy(msg, 13, c.stderrBuffer, c.stderrWritepos, len); | 786 System.arraycopy(msg, 13, c.stderrBuffer, c.stderrWritepos, len); |
786 c.stderrWritepos += len; | 787 c.stderrWritepos += len; |
787 | |
788 c.notifyAll(); | 788 c.notifyAll(); |
789 } | 789 } |
790 } | 790 } |
791 | 791 |
792 /** | 792 /** |
799 */ | 799 */ |
800 public int waitForCondition(Channel c, long timeout, int condition_mask) throws IOException { | 800 public int waitForCondition(Channel c, long timeout, int condition_mask) throws IOException { |
801 long end_time = 0; | 801 long end_time = 0; |
802 boolean end_time_set = false; | 802 boolean end_time_set = false; |
803 | 803 |
804 synchronized(c) { | 804 synchronized (c) { |
805 while(true) { | 805 while (true) { |
806 int current_cond = 0; | 806 int current_cond = 0; |
807 | |
808 int stdoutAvail = c.stdoutWritepos - c.stdoutReadpos; | 807 int stdoutAvail = c.stdoutWritepos - c.stdoutReadpos; |
809 int stderrAvail = c.stderrWritepos - c.stderrReadpos; | 808 int stderrAvail = c.stderrWritepos - c.stderrReadpos; |
810 | 809 |
811 if(stdoutAvail > 0) { | 810 if (stdoutAvail > 0) { |
812 current_cond = current_cond | ChannelCondition.STDOUT_DATA; | 811 current_cond = current_cond | ChannelCondition.STDOUT_DATA; |
813 } | 812 } |
814 | 813 |
815 if(stderrAvail > 0) { | 814 if (stderrAvail > 0) { |
816 current_cond = current_cond | ChannelCondition.STDERR_DATA; | 815 current_cond = current_cond | ChannelCondition.STDERR_DATA; |
817 } | 816 } |
818 | 817 |
819 if(c.EOF) { | 818 if (c.EOF) { |
820 current_cond = current_cond | ChannelCondition.EOF; | 819 current_cond = current_cond | ChannelCondition.EOF; |
821 } | 820 } |
822 | 821 |
823 if(c.getExitStatus() != null) { | 822 if (c.getExitStatus() != null) { |
824 current_cond = current_cond | ChannelCondition.EXIT_STATUS; | 823 current_cond = current_cond | ChannelCondition.EXIT_STATUS; |
825 } | 824 } |
826 | 825 |
827 if(c.getExitSignal() != null) { | 826 if (c.getExitSignal() != null) { |
828 current_cond = current_cond | ChannelCondition.EXIT_SIGNAL; | 827 current_cond = current_cond | ChannelCondition.EXIT_SIGNAL; |
829 } | 828 } |
830 | 829 |
831 if(c.state == Channel.STATE_CLOSED) { | 830 if (c.state == Channel.STATE_CLOSED) { |
832 return current_cond | ChannelCondition.CLOSED | ChannelCondition.EOF; | 831 return current_cond | ChannelCondition.CLOSED | ChannelCondition.EOF; |
833 } | 832 } |
834 | 833 |
835 if((current_cond & condition_mask) != 0) { | 834 if ((current_cond & condition_mask) != 0) { |
836 return current_cond; | 835 return current_cond; |
837 } | 836 } |
838 | 837 |
839 if(timeout > 0) { | 838 if (timeout > 0) { |
840 if(!end_time_set) { | 839 if (!end_time_set) { |
841 end_time = System.currentTimeMillis() + timeout; | 840 end_time = System.currentTimeMillis() + timeout; |
842 end_time_set = true; | 841 end_time_set = true; |
843 } | 842 } |
844 else { | 843 else { |
845 timeout = end_time - System.currentTimeMillis(); | 844 timeout = end_time - System.currentTimeMillis(); |
846 | 845 |
847 if(timeout <= 0) { | 846 if (timeout <= 0) { |
848 return current_cond | ChannelCondition.TIMEOUT; | 847 return current_cond | ChannelCondition.TIMEOUT; |
849 } | 848 } |
850 } | 849 } |
851 } | 850 } |
852 | 851 |
853 try { | 852 try { |
854 if(timeout > 0) { | 853 if (timeout > 0) { |
855 c.wait(timeout); | 854 c.wait(timeout); |
856 } | 855 } |
857 else { | 856 else { |
858 c.wait(); | 857 c.wait(); |
859 } | 858 } |
860 } | 859 } |
861 catch(InterruptedException e) { | 860 catch (InterruptedException e) { |
862 throw new InterruptedIOException(e.getMessage()); | 861 throw new InterruptedIOException(e.getMessage()); |
863 } | 862 } |
864 } | 863 } |
865 } | 864 } |
866 } | 865 } |
867 | 866 |
868 public int getAvailable(Channel c, boolean extended) throws IOException { | 867 public int getAvailable(Channel c, boolean extended) throws IOException { |
869 synchronized(c) { | 868 synchronized (c) { |
870 int avail; | 869 int avail; |
871 | 870 |
872 if(extended) { | 871 if (extended) { |
873 avail = c.stderrWritepos - c.stderrReadpos; | 872 avail = c.stderrWritepos - c.stderrReadpos; |
874 } | 873 } |
875 else { | 874 else { |
876 avail = c.stdoutWritepos - c.stdoutReadpos; | 875 avail = c.stdoutWritepos - c.stdoutReadpos; |
877 } | 876 } |
884 int copylen = 0; | 883 int copylen = 0; |
885 int increment = 0; | 884 int increment = 0; |
886 int remoteID = 0; | 885 int remoteID = 0; |
887 int localID = 0; | 886 int localID = 0; |
888 | 887 |
889 synchronized(c) { | 888 synchronized (c) { |
890 int stdoutAvail = 0; | 889 int stdoutAvail = 0; |
891 int stderrAvail = 0; | 890 int stderrAvail = 0; |
892 | 891 |
893 while(true) { | 892 while (true) { |
894 /* | 893 /* |
895 * Data available? We have to return remaining data even if the | 894 * Data available? We have to return remaining data even if the |
896 * channel is already closed. | 895 * channel is already closed. |
897 */ | 896 */ |
898 | |
899 stdoutAvail = c.stdoutWritepos - c.stdoutReadpos; | 897 stdoutAvail = c.stdoutWritepos - c.stdoutReadpos; |
900 stderrAvail = c.stderrWritepos - c.stderrReadpos; | 898 stderrAvail = c.stderrWritepos - c.stderrReadpos; |
901 | 899 |
902 if((!extended) && (stdoutAvail != 0)) { | 900 if ((!extended) && (stdoutAvail != 0)) { |
903 break; | 901 break; |
904 } | 902 } |
905 | 903 |
906 if((extended) && (stderrAvail != 0)) { | 904 if ((extended) && (stderrAvail != 0)) { |
907 break; | 905 break; |
908 } | 906 } |
909 | 907 |
910 /* Do not wait if more data will never arrive (EOF or CLOSED) */ | 908 /* Do not wait if more data will never arrive (EOF or CLOSED) */ |
911 | 909 |
912 if((c.EOF) || (c.state != Channel.STATE_OPEN)) { | 910 if ((c.EOF) || (c.state != Channel.STATE_OPEN)) { |
913 return -1; | 911 return -1; |
914 } | 912 } |
915 | 913 |
916 try { | 914 try { |
917 c.wait(); | 915 c.wait(); |
918 } | 916 } |
919 catch(InterruptedException e) { | 917 catch (InterruptedException e) { |
920 throw new InterruptedIOException(e.getMessage()); | 918 throw new InterruptedIOException(e.getMessage()); |
921 } | 919 } |
922 } | 920 } |
923 | 921 |
924 /* OK, there is some data. Return it. */ | 922 /* OK, there is some data. Return it. */ |
925 | 923 |
926 if(!extended) { | 924 if (!extended) { |
927 copylen = (stdoutAvail > len) ? len : stdoutAvail; | 925 copylen = (stdoutAvail > len) ? len : stdoutAvail; |
928 System.arraycopy(c.stdoutBuffer, c.stdoutReadpos, target, off, copylen); | 926 System.arraycopy(c.stdoutBuffer, c.stdoutReadpos, target, off, copylen); |
929 c.stdoutReadpos += copylen; | 927 c.stdoutReadpos += copylen; |
930 | 928 |
931 if(c.stdoutReadpos != c.stdoutWritepos) | 929 if (c.stdoutReadpos != c.stdoutWritepos) { |
932 | |
933 { | |
934 System.arraycopy(c.stdoutBuffer, c.stdoutReadpos, c.stdoutBuffer, 0, c.stdoutWritepos | 930 System.arraycopy(c.stdoutBuffer, c.stdoutReadpos, c.stdoutBuffer, 0, c.stdoutWritepos |
935 - c.stdoutReadpos); | 931 - c.stdoutReadpos); |
936 } | 932 } |
937 | 933 |
938 c.stdoutWritepos -= c.stdoutReadpos; | 934 c.stdoutWritepos -= c.stdoutReadpos; |
939 c.stdoutReadpos = 0; | 935 c.stdoutReadpos = 0; |
940 } | 936 } |
941 else { | 937 else { |
942 copylen = (stderrAvail > len) ? len : stderrAvail; | 938 copylen = (stderrAvail > len) ? len : stderrAvail; |
943 System.arraycopy(c.stderrBuffer, c.stderrReadpos, target, off, copylen); | 939 System.arraycopy(c.stderrBuffer, c.stderrReadpos, target, off, copylen); |
944 c.stderrReadpos += copylen; | 940 c.stderrReadpos += copylen; |
945 | 941 |
946 if(c.stderrReadpos != c.stderrWritepos) | 942 if (c.stderrReadpos != c.stderrWritepos) { |
947 | |
948 { | |
949 System.arraycopy(c.stderrBuffer, c.stderrReadpos, c.stderrBuffer, 0, c.stderrWritepos | 943 System.arraycopy(c.stderrBuffer, c.stderrReadpos, c.stderrBuffer, 0, c.stderrWritepos |
950 - c.stderrReadpos); | 944 - c.stderrReadpos); |
951 } | 945 } |
952 | 946 |
953 c.stderrWritepos -= c.stderrReadpos; | 947 c.stderrWritepos -= c.stderrReadpos; |
954 c.stderrReadpos = 0; | 948 c.stderrReadpos = 0; |
955 } | 949 } |
956 | 950 |
957 if(c.state != Channel.STATE_OPEN) { | 951 if (c.state != Channel.STATE_OPEN) { |
958 return copylen; | 952 return copylen; |
959 } | 953 } |
960 | 954 |
961 if(c.localWindow < ((Channel.CHANNEL_BUFFER_SIZE + 1) / 2)) { | 955 if (c.localWindow < ((Channel.CHANNEL_BUFFER_SIZE + 1) / 2)) { |
962 int minFreeSpace = Math.min(Channel.CHANNEL_BUFFER_SIZE - c.stdoutWritepos, | 956 int minFreeSpace = Math.min(Channel.CHANNEL_BUFFER_SIZE - c.stdoutWritepos, |
963 Channel.CHANNEL_BUFFER_SIZE - c.stderrWritepos); | 957 Channel.CHANNEL_BUFFER_SIZE - c.stderrWritepos); |
964 | |
965 increment = minFreeSpace - c.localWindow; | 958 increment = minFreeSpace - c.localWindow; |
966 c.localWindow = minFreeSpace; | 959 c.localWindow = minFreeSpace; |
967 } | 960 } |
968 | 961 |
969 remoteID = c.remoteID; /* read while holding the lock */ | 962 remoteID = c.remoteID; /* read while holding the lock */ |
974 * If a consumer reads stdout and stdin in parallel, we may end up with | 967 * If a consumer reads stdout and stdin in parallel, we may end up with |
975 * sending two msgWindowAdjust messages. Luckily, it | 968 * sending two msgWindowAdjust messages. Luckily, it |
976 * does not matter in which order they arrive at the server. | 969 * does not matter in which order they arrive at the server. |
977 */ | 970 */ |
978 | 971 |
979 if(increment > 0) { | 972 if (increment > 0) { |
980 log.debug("Sending SSH_MSG_CHANNEL_WINDOW_ADJUST (channel " + localID + ", " + increment + ")"); | 973 log.debug("Sending SSH_MSG_CHANNEL_WINDOW_ADJUST (channel " + localID + ", " + increment + ")"); |
981 | 974 |
982 synchronized(c.channelSendLock) { | 975 synchronized (c.channelSendLock) { |
983 byte[] msg = c.msgWindowAdjust; | 976 byte[] msg = c.msgWindowAdjust; |
984 | |
985 msg[0] = Packets.SSH_MSG_CHANNEL_WINDOW_ADJUST; | 977 msg[0] = Packets.SSH_MSG_CHANNEL_WINDOW_ADJUST; |
986 msg[1] = (byte) (remoteID >> 24); | 978 msg[1] = (byte)(remoteID >> 24); |
987 msg[2] = (byte) (remoteID >> 16); | 979 msg[2] = (byte)(remoteID >> 16); |
988 msg[3] = (byte) (remoteID >> 8); | 980 msg[3] = (byte)(remoteID >> 8); |
989 msg[4] = (byte) (remoteID); | 981 msg[4] = (byte)(remoteID); |
990 msg[5] = (byte) (increment >> 24); | 982 msg[5] = (byte)(increment >> 24); |
991 msg[6] = (byte) (increment >> 16); | 983 msg[6] = (byte)(increment >> 16); |
992 msg[7] = (byte) (increment >> 8); | 984 msg[7] = (byte)(increment >> 8); |
993 msg[8] = (byte) (increment); | 985 msg[8] = (byte)(increment); |
994 | 986 |
995 if(!c.closeMessageSent) { | 987 if (!c.closeMessageSent) { |
996 tm.sendMessage(msg); | 988 tm.sendMessage(msg); |
997 } | 989 } |
998 } | 990 } |
999 } | 991 } |
1000 | 992 |
1001 return copylen; | 993 return copylen; |
1002 } | 994 } |
1003 | 995 |
1004 public void msgChannelData(byte[] msg) throws IOException { | 996 public void msgChannelData(byte[] msg) throws IOException { |
1005 if(msg.length <= 9) { | 997 if (msg.length <= 9) { |
1006 throw new PacketFormatException(String.format("SSH_MSG_CHANNEL_DATA message has wrong size (%d)", msg.length)); | 998 throw new PacketFormatException(String.format("SSH_MSG_CHANNEL_DATA message has wrong size (%d)", msg.length)); |
1007 } | 999 } |
1008 | 1000 |
1009 int id = ((msg[1] & 0xff) << 24) | ((msg[2] & 0xff) << 16) | ((msg[3] & 0xff) << 8) | (msg[4] & 0xff); | 1001 int id = ((msg[1] & 0xff) << 24) | ((msg[2] & 0xff) << 16) | ((msg[3] & 0xff) << 8) | (msg[4] & 0xff); |
1010 int len = ((msg[5] & 0xff) << 24) | ((msg[6] & 0xff) << 16) | ((msg[7] & 0xff) << 8) | (msg[8] & 0xff); | 1002 int len = ((msg[5] & 0xff) << 24) | ((msg[6] & 0xff) << 16) | ((msg[7] & 0xff) << 8) | (msg[8] & 0xff); |
1011 | |
1012 Channel c = getChannel(id); | 1003 Channel c = getChannel(id); |
1013 | 1004 |
1014 if(c == null) { | 1005 if (c == null) { |
1015 throw new PacketTypeException("Unexpected SSH_MSG_CHANNEL_DATA message for non-existent channel " + id); | 1006 throw new PacketTypeException("Unexpected SSH_MSG_CHANNEL_DATA message for non-existent channel " + id); |
1016 } | 1007 } |
1017 | 1008 |
1018 if(len != (msg.length - 9)) { | 1009 if (len != (msg.length - 9)) { |
1019 throw new PacketFormatException("SSH_MSG_CHANNEL_DATA message has wrong len (calculated " + (msg.length - 9) + ", got " | 1010 throw new PacketFormatException("SSH_MSG_CHANNEL_DATA message has wrong len (calculated " + (msg.length - 9) + ", got " |
1020 + len + ")"); | 1011 + len + ")"); |
1021 } | 1012 } |
1022 | 1013 |
1023 log.debug("Got SSH_MSG_CHANNEL_DATA (channel " + id + ", " + len + ")"); | 1014 log.debug("Got SSH_MSG_CHANNEL_DATA (channel " + id + ", " + len + ")"); |
1024 | 1015 |
1025 synchronized(c) { | 1016 synchronized (c) { |
1026 if(c.state == Channel.STATE_CLOSED) { | 1017 if (c.state == Channel.STATE_CLOSED) { |
1027 return; // ignore | 1018 return; // ignore |
1028 } | 1019 } |
1029 | 1020 |
1030 if(c.state != Channel.STATE_OPEN) { | 1021 if (c.state != Channel.STATE_OPEN) { |
1031 throw new PacketTypeException("Got SSH_MSG_CHANNEL_DATA, but channel is not in correct state (" + c.state + ")"); | 1022 throw new PacketTypeException("Got SSH_MSG_CHANNEL_DATA, but channel is not in correct state (" + c.state + ")"); |
1032 } | 1023 } |
1033 | 1024 |
1034 if(c.localWindow < len) { | 1025 if (c.localWindow < len) { |
1035 throw new IOException("Remote sent too much data, does not fit into window."); | 1026 throw new IOException("Remote sent too much data, does not fit into window."); |
1036 } | 1027 } |
1037 | 1028 |
1038 c.localWindow -= len; | 1029 c.localWindow -= len; |
1039 | |
1040 System.arraycopy(msg, 9, c.stdoutBuffer, c.stdoutWritepos, len); | 1030 System.arraycopy(msg, 9, c.stdoutBuffer, c.stdoutWritepos, len); |
1041 c.stdoutWritepos += len; | 1031 c.stdoutWritepos += len; |
1042 | |
1043 c.notifyAll(); | 1032 c.notifyAll(); |
1044 } | 1033 } |
1045 } | 1034 } |
1046 | 1035 |
1047 public void msgChannelWindowAdjust(byte[] msg) throws IOException { | 1036 public void msgChannelWindowAdjust(byte[] msg) throws IOException { |
1048 if(msg.length != 9) { | 1037 if (msg.length != 9) { |
1049 throw new PacketFormatException(String.format("SSH_MSG_CHANNEL_WINDOW_ADJUST message has wrong size (%d)", msg.length)); | 1038 throw new PacketFormatException(String.format("SSH_MSG_CHANNEL_WINDOW_ADJUST message has wrong size (%d)", msg.length)); |
1050 } | 1039 } |
1051 | 1040 |
1052 int id = ((msg[1] & 0xff) << 24) | ((msg[2] & 0xff) << 16) | ((msg[3] & 0xff) << 8) | (msg[4] & 0xff); | 1041 int id = ((msg[1] & 0xff) << 24) | ((msg[2] & 0xff) << 16) | ((msg[3] & 0xff) << 8) | (msg[4] & 0xff); |
1053 int windowChange = ((msg[5] & 0xff) << 24) | ((msg[6] & 0xff) << 16) | ((msg[7] & 0xff) << 8) | (msg[8] & 0xff); | 1042 int windowChange = ((msg[5] & 0xff) << 24) | ((msg[6] & 0xff) << 16) | ((msg[7] & 0xff) << 8) | (msg[8] & 0xff); |
1054 | |
1055 Channel c = getChannel(id); | 1043 Channel c = getChannel(id); |
1056 | 1044 |
1057 if(c == null) { | 1045 if (c == null) { |
1058 throw new PacketTypeException("Unexpected SSH_MSG_CHANNEL_WINDOW_ADJUST message for non-existent channel " + id); | 1046 throw new PacketTypeException("Unexpected SSH_MSG_CHANNEL_WINDOW_ADJUST message for non-existent channel " + id); |
1059 } | 1047 } |
1060 | 1048 |
1061 synchronized(c) { | 1049 synchronized (c) { |
1062 final long huge = 0xFFFFffffL; /* 2^32 - 1 */ | 1050 final long huge = 0xFFFFffffL; /* 2^32 - 1 */ |
1063 | |
1064 c.remoteWindow += (windowChange & huge); /* avoid sign extension */ | 1051 c.remoteWindow += (windowChange & huge); /* avoid sign extension */ |
1065 | 1052 |
1066 /* TODO - is this a good heuristic? */ | 1053 /* TODO - is this a good heuristic? */ |
1067 | 1054 |
1068 if((c.remoteWindow > huge)) { | 1055 if ((c.remoteWindow > huge)) { |
1069 c.remoteWindow = huge; | 1056 c.remoteWindow = huge; |
1070 } | 1057 } |
1071 | 1058 |
1072 c.notifyAll(); | 1059 c.notifyAll(); |
1073 } | 1060 } |
1074 | |
1075 | 1061 |
1076 log.debug("Got SSH_MSG_CHANNEL_WINDOW_ADJUST (channel " + id + ", " + windowChange + ")"); | 1062 log.debug("Got SSH_MSG_CHANNEL_WINDOW_ADJUST (channel " + id + ", " + windowChange + ")"); |
1077 } | 1063 } |
1078 | 1064 |
1079 public void msgChannelOpen(byte[] msg) throws IOException { | 1065 public void msgChannelOpen(byte[] msg) throws IOException { |
1080 TypesReader tr = new TypesReader(msg); | 1066 TypesReader tr = new TypesReader(msg); |
1081 | |
1082 tr.readByte(); // skip packet type | 1067 tr.readByte(); // skip packet type |
1083 String channelType = tr.readString(); | 1068 String channelType = tr.readString(); |
1084 int remoteID = tr.readUINT32(); /* sender channel */ | 1069 int remoteID = tr.readUINT32(); /* sender channel */ |
1085 int remoteWindow = tr.readUINT32(); /* initial window size */ | 1070 int remoteWindow = tr.readUINT32(); /* initial window size */ |
1086 int remoteMaxPacketSize = tr.readUINT32(); /* maximum packet size */ | 1071 int remoteMaxPacketSize = tr.readUINT32(); /* maximum packet size */ |
1087 | 1072 |
1088 if("x11".equals(channelType)) { | 1073 if ("x11".equals(channelType)) { |
1089 synchronized(x11_magic_cookies) { | 1074 synchronized (x11_magic_cookies) { |
1090 /* If we did not request X11 forwarding, then simply ignore this bogus request. */ | 1075 /* If we did not request X11 forwarding, then simply ignore this bogus request. */ |
1091 | 1076 if (x11_magic_cookies.size() == 0) { |
1092 if(x11_magic_cookies.size() == 0) { | |
1093 PacketChannelOpenFailure pcof = new PacketChannelOpenFailure(remoteID, | 1077 PacketChannelOpenFailure pcof = new PacketChannelOpenFailure(remoteID, |
1094 Packets.SSH_OPEN_ADMINISTRATIVELY_PROHIBITED, "X11 forwarding not activated", ""); | 1078 Packets.SSH_OPEN_ADMINISTRATIVELY_PROHIBITED, "X11 forwarding not activated", ""); |
1095 | |
1096 tm.sendAsynchronousMessage(pcof.getPayload()); | 1079 tm.sendAsynchronousMessage(pcof.getPayload()); |
1097 | |
1098 log.warning("Unexpected X11 request, denying it!"); | 1080 log.warning("Unexpected X11 request, denying it!"); |
1099 | |
1100 return; | 1081 return; |
1101 } | 1082 } |
1102 } | 1083 } |
1103 | 1084 |
1104 String remoteOriginatorAddress = tr.readString(); | 1085 String remoteOriginatorAddress = tr.readString(); |
1105 int remoteOriginatorPort = tr.readUINT32(); | 1086 int remoteOriginatorPort = tr.readUINT32(); |
1106 | |
1107 Channel c = new Channel(this); | 1087 Channel c = new Channel(this); |
1108 | 1088 |
1109 synchronized(c) { | 1089 synchronized (c) { |
1110 c.remoteID = remoteID; | 1090 c.remoteID = remoteID; |
1111 c.remoteWindow = remoteWindow & 0xFFFFffffL; /* properly convert UINT32 to long */ | 1091 c.remoteWindow = remoteWindow & 0xFFFFffffL; /* properly convert UINT32 to long */ |
1112 c.remoteMaxPacketSize = remoteMaxPacketSize; | 1092 c.remoteMaxPacketSize = remoteMaxPacketSize; |
1113 c.localID = addChannel(c); | 1093 c.localID = addChannel(c); |
1114 } | 1094 } |
1115 | 1095 |
1116 /* | 1096 /* |
1117 * The open confirmation message will be sent from another thread | 1097 * The open confirmation message will be sent from another thread |
1118 */ | 1098 */ |
1119 | |
1120 RemoteX11AcceptThread rxat = new RemoteX11AcceptThread(c, remoteOriginatorAddress, remoteOriginatorPort); | 1099 RemoteX11AcceptThread rxat = new RemoteX11AcceptThread(c, remoteOriginatorAddress, remoteOriginatorPort); |
1121 rxat.setDaemon(true); | 1100 rxat.setDaemon(true); |
1122 rxat.start(); | 1101 rxat.start(); |
1123 | |
1124 return; | 1102 return; |
1125 } | 1103 } |
1126 | 1104 |
1127 if("forwarded-tcpip".equals(channelType)) { | 1105 if ("forwarded-tcpip".equals(channelType)) { |
1128 String remoteConnectedAddress = tr.readString(); /* address that was connected */ | 1106 String remoteConnectedAddress = tr.readString(); /* address that was connected */ |
1129 int remoteConnectedPort = tr.readUINT32(); /* port that was connected */ | 1107 int remoteConnectedPort = tr.readUINT32(); /* port that was connected */ |
1130 String remoteOriginatorAddress = tr.readString(); /* originator IP address */ | 1108 String remoteOriginatorAddress = tr.readString(); /* originator IP address */ |
1131 int remoteOriginatorPort = tr.readUINT32(); /* originator port */ | 1109 int remoteOriginatorPort = tr.readUINT32(); /* originator port */ |
1132 | |
1133 RemoteForwardingData rfd; | 1110 RemoteForwardingData rfd; |
1134 | 1111 |
1135 synchronized(remoteForwardings) { | 1112 synchronized (remoteForwardings) { |
1136 rfd = remoteForwardings.get(remoteConnectedPort); | 1113 rfd = remoteForwardings.get(remoteConnectedPort); |
1137 } | 1114 } |
1138 | 1115 |
1139 if(rfd == null) { | 1116 if (rfd == null) { |
1140 PacketChannelOpenFailure pcof = new PacketChannelOpenFailure(remoteID, | 1117 PacketChannelOpenFailure pcof = new PacketChannelOpenFailure(remoteID, |
1141 Packets.SSH_OPEN_ADMINISTRATIVELY_PROHIBITED, | 1118 Packets.SSH_OPEN_ADMINISTRATIVELY_PROHIBITED, |
1142 "No thanks, unknown port in forwarded-tcpip request", ""); | 1119 "No thanks, unknown port in forwarded-tcpip request", ""); |
1143 | 1120 /* Always try to be polite. */ |
1144 /* Always try to be polite. */ | |
1145 | |
1146 tm.sendAsynchronousMessage(pcof.getPayload()); | 1121 tm.sendAsynchronousMessage(pcof.getPayload()); |
1147 | |
1148 log.debug("Unexpected forwarded-tcpip request, denying it!"); | 1122 log.debug("Unexpected forwarded-tcpip request, denying it!"); |
1149 | |
1150 return; | 1123 return; |
1151 } | 1124 } |
1152 | 1125 |
1153 Channel c = new Channel(this); | 1126 Channel c = new Channel(this); |
1154 | 1127 |
1155 synchronized(c) { | 1128 synchronized (c) { |
1156 c.remoteID = remoteID; | 1129 c.remoteID = remoteID; |
1157 c.remoteWindow = remoteWindow & 0xFFFFffffL; /* convert UINT32 to long */ | 1130 c.remoteWindow = remoteWindow & 0xFFFFffffL; /* convert UINT32 to long */ |
1158 c.remoteMaxPacketSize = remoteMaxPacketSize; | 1131 c.remoteMaxPacketSize = remoteMaxPacketSize; |
1159 c.localID = addChannel(c); | 1132 c.localID = addChannel(c); |
1160 } | 1133 } |
1161 | 1134 |
1162 /* | 1135 /* |
1163 * The open confirmation message will be sent from another thread. | 1136 * The open confirmation message will be sent from another thread. |
1164 */ | 1137 */ |
1165 | |
1166 RemoteAcceptThread rat = new RemoteAcceptThread(c, remoteConnectedAddress, remoteConnectedPort, | 1138 RemoteAcceptThread rat = new RemoteAcceptThread(c, remoteConnectedAddress, remoteConnectedPort, |
1167 remoteOriginatorAddress, remoteOriginatorPort, rfd.targetAddress, rfd.targetPort); | 1139 remoteOriginatorAddress, remoteOriginatorPort, rfd.targetAddress, rfd.targetPort); |
1168 | |
1169 rat.setDaemon(true); | 1140 rat.setDaemon(true); |
1170 rat.start(); | 1141 rat.start(); |
1171 | |
1172 return; | 1142 return; |
1173 } | 1143 } |
1174 | 1144 |
1175 if((server_state != null) && ("session".equals(channelType))) { | 1145 if ((server_state != null) && ("session".equals(channelType))) { |
1176 ServerConnectionCallback cb; | 1146 ServerConnectionCallback cb; |
1177 | 1147 |
1178 synchronized(server_state) { | 1148 synchronized (server_state) { |
1179 cb = server_state.cb_conn; | 1149 cb = server_state.cb_conn; |
1180 } | 1150 } |
1181 | 1151 |
1182 if(cb == null) { | 1152 if (cb == null) { |
1183 tm.sendAsynchronousMessage(new PacketChannelOpenFailure(remoteID, Packets.SSH_OPEN_ADMINISTRATIVELY_PROHIBITED, | 1153 tm.sendAsynchronousMessage(new PacketChannelOpenFailure(remoteID, Packets.SSH_OPEN_ADMINISTRATIVELY_PROHIBITED, |
1184 "Sessions are currently not enabled", "en").getPayload()); | 1154 "Sessions are currently not enabled", "en").getPayload()); |
1185 | |
1186 return; | 1155 return; |
1187 } | 1156 } |
1188 | 1157 |
1189 final Channel c = new Channel(this); | 1158 final Channel c = new Channel(this); |
1190 | 1159 |
1191 synchronized(c) { | 1160 synchronized (c) { |
1192 c.remoteID = remoteID; | 1161 c.remoteID = remoteID; |
1193 c.remoteWindow = remoteWindow & 0xFFFFffffL; /* convert UINT32 to long */ | 1162 c.remoteWindow = remoteWindow & 0xFFFFffffL; /* convert UINT32 to long */ |
1194 c.remoteMaxPacketSize = remoteMaxPacketSize; | 1163 c.remoteMaxPacketSize = remoteMaxPacketSize; |
1195 c.localID = addChannel(c); | 1164 c.localID = addChannel(c); |
1196 c.state = Channel.STATE_OPEN; | 1165 c.state = Channel.STATE_OPEN; |
1197 c.ss = new ServerSessionImpl(c); | 1166 c.ss = new ServerSessionImpl(c); |
1198 } | 1167 } |
1199 | 1168 |
1200 PacketChannelOpenConfirmation pcoc = new PacketChannelOpenConfirmation(c.remoteID, c.localID, | 1169 PacketChannelOpenConfirmation pcoc = new PacketChannelOpenConfirmation(c.remoteID, c.localID, |
1201 c.localWindow, c.localMaxPacketSize); | 1170 c.localWindow, c.localMaxPacketSize); |
1202 | |
1203 tm.sendAsynchronousMessage(pcoc.getPayload()); | 1171 tm.sendAsynchronousMessage(pcoc.getPayload()); |
1204 | |
1205 c.ss.sscb = cb.acceptSession(c.ss); | 1172 c.ss.sscb = cb.acceptSession(c.ss); |
1206 | |
1207 return; | 1173 return; |
1208 } | 1174 } |
1209 | 1175 |
1210 /* Tell the server that we have no idea what it is talking about */ | 1176 /* Tell the server that we have no idea what it is talking about */ |
1211 | |
1212 PacketChannelOpenFailure pcof = new PacketChannelOpenFailure(remoteID, Packets.SSH_OPEN_UNKNOWN_CHANNEL_TYPE, | 1177 PacketChannelOpenFailure pcof = new PacketChannelOpenFailure(remoteID, Packets.SSH_OPEN_UNKNOWN_CHANNEL_TYPE, |
1213 "Unknown channel type", ""); | 1178 "Unknown channel type", ""); |
1214 | |
1215 tm.sendAsynchronousMessage(pcof.getPayload()); | 1179 tm.sendAsynchronousMessage(pcof.getPayload()); |
1216 | |
1217 | |
1218 log.warning("The peer tried to open an unsupported channel type (" + channelType + ")"); | 1180 log.warning("The peer tried to open an unsupported channel type (" + channelType + ")"); |
1219 } | 1181 } |
1220 | 1182 |
1221 /* Starts the given runnable in a foreground (non-daemon) thread */ | 1183 /* Starts the given runnable in a foreground (non-daemon) thread */ |
1222 private void runAsync(Runnable r) { | 1184 private void runAsync(Runnable r) { |
1224 t.start(); | 1186 t.start(); |
1225 } | 1187 } |
1226 | 1188 |
1227 public void msgChannelRequest(byte[] msg) throws IOException { | 1189 public void msgChannelRequest(byte[] msg) throws IOException { |
1228 TypesReader tr = new TypesReader(msg); | 1190 TypesReader tr = new TypesReader(msg); |
1229 | |
1230 tr.readByte(); // skip packet type | 1191 tr.readByte(); // skip packet type |
1231 int id = tr.readUINT32(); | 1192 int id = tr.readUINT32(); |
1232 | |
1233 Channel c = getChannel(id); | 1193 Channel c = getChannel(id); |
1234 | 1194 |
1235 if(c == null) { | 1195 if (c == null) { |
1236 throw new IOException("Unexpected SSH_MSG_CHANNEL_REQUEST message for non-existent channel " + id); | 1196 throw new IOException("Unexpected SSH_MSG_CHANNEL_REQUEST message for non-existent channel " + id); |
1237 } | 1197 } |
1238 | 1198 |
1239 ServerSessionImpl server_session = null; | 1199 ServerSessionImpl server_session = null; |
1240 | 1200 |
1241 if(server_state != null) { | 1201 if (server_state != null) { |
1242 synchronized(c) { | 1202 synchronized (c) { |
1243 server_session = c.ss; | 1203 server_session = c.ss; |
1244 } | 1204 } |
1245 } | 1205 } |
1246 | 1206 |
1247 String type = tr.readString("US-ASCII"); | 1207 String type = tr.readString("US-ASCII"); |
1248 boolean wantReply = tr.readBoolean(); | 1208 boolean wantReply = tr.readBoolean(); |
1249 | |
1250 log.debug("Got SSH_MSG_CHANNEL_REQUEST (channel " + id + ", '" + type + "')"); | 1209 log.debug("Got SSH_MSG_CHANNEL_REQUEST (channel " + id + ", '" + type + "')"); |
1251 | 1210 |
1252 if(type.equals("exit-status")) { | 1211 if (type.equals("exit-status")) { |
1253 if(wantReply) { | 1212 if (wantReply) { |
1254 throw new IOException( | 1213 throw new IOException( |
1255 "Badly formatted SSH_MSG_CHANNEL_REQUEST exit-status message, 'want reply' is true"); | 1214 "Badly formatted SSH_MSG_CHANNEL_REQUEST exit-status message, 'want reply' is true"); |
1256 } | 1215 } |
1257 | 1216 |
1258 int exit_status = tr.readUINT32(); | 1217 int exit_status = tr.readUINT32(); |
1259 | 1218 |
1260 if(tr.remain() != 0) { | 1219 if (tr.remain() != 0) { |
1261 throw new IOException("Badly formatted SSH_MSG_CHANNEL_REQUEST message"); | 1220 throw new IOException("Badly formatted SSH_MSG_CHANNEL_REQUEST message"); |
1262 } | 1221 } |
1263 | 1222 |
1264 synchronized(c) { | 1223 synchronized (c) { |
1265 c.exit_status = exit_status; | 1224 c.exit_status = exit_status; |
1266 c.notifyAll(); | 1225 c.notifyAll(); |
1267 } | 1226 } |
1268 | 1227 |
1269 log.debug("Got EXIT STATUS (channel " + id + ", status " + exit_status + ")"); | 1228 log.debug("Got EXIT STATUS (channel " + id + ", status " + exit_status + ")"); |
1270 | |
1271 return; | 1229 return; |
1272 } | 1230 } |
1273 | 1231 |
1274 if((server_state == null) && (type.equals("exit-signal"))) { | 1232 if ((server_state == null) && (type.equals("exit-signal"))) { |
1275 if(wantReply) { | 1233 if (wantReply) { |
1276 throw new IOException( | 1234 throw new IOException( |
1277 "Badly formatted SSH_MSG_CHANNEL_REQUEST exit-signal message, 'want reply' is true"); | 1235 "Badly formatted SSH_MSG_CHANNEL_REQUEST exit-signal message, 'want reply' is true"); |
1278 } | 1236 } |
1279 | 1237 |
1280 String signame = tr.readString("US-ASCII"); | 1238 String signame = tr.readString("US-ASCII"); |
1281 tr.readBoolean(); | 1239 tr.readBoolean(); |
1282 tr.readString(); | 1240 tr.readString(); |
1283 tr.readString(); | 1241 tr.readString(); |
1284 | 1242 |
1285 if(tr.remain() != 0) { | 1243 if (tr.remain() != 0) { |
1286 throw new IOException("Badly formatted SSH_MSG_CHANNEL_REQUEST message"); | 1244 throw new IOException("Badly formatted SSH_MSG_CHANNEL_REQUEST message"); |
1287 } | 1245 } |
1288 | 1246 |
1289 synchronized(c) { | 1247 synchronized (c) { |
1290 c.exit_signal = signame; | 1248 c.exit_signal = signame; |
1291 c.notifyAll(); | 1249 c.notifyAll(); |
1292 } | 1250 } |
1293 | 1251 |
1294 log.debug("Got EXIT SIGNAL (channel " + id + ", signal " + signame + ")"); | 1252 log.debug("Got EXIT SIGNAL (channel " + id + ", signal " + signame + ")"); |
1295 | |
1296 return; | 1253 return; |
1297 } | 1254 } |
1298 | 1255 |
1299 if((server_session != null) && (type.equals("pty-req"))) { | 1256 if ((server_session != null) && (type.equals("pty-req"))) { |
1300 PtySettings pty = new PtySettings(); | 1257 PtySettings pty = new PtySettings(); |
1301 | |
1302 pty.term = tr.readString(); | 1258 pty.term = tr.readString(); |
1303 pty.term_width_characters = tr.readUINT32(); | 1259 pty.term_width_characters = tr.readUINT32(); |
1304 pty.term_height_characters = tr.readUINT32(); | 1260 pty.term_height_characters = tr.readUINT32(); |
1305 pty.term_width_pixels = tr.readUINT32(); | 1261 pty.term_width_pixels = tr.readUINT32(); |
1306 pty.term_height_pixels = tr.readUINT32(); | 1262 pty.term_height_pixels = tr.readUINT32(); |
1307 pty.terminal_modes = tr.readByteString(); | 1263 pty.terminal_modes = tr.readByteString(); |
1308 | 1264 |
1309 if(tr.remain() != 0) { | 1265 if (tr.remain() != 0) { |
1310 throw new IOException("Badly formatted SSH_MSG_CHANNEL_REQUEST message"); | 1266 throw new IOException("Badly formatted SSH_MSG_CHANNEL_REQUEST message"); |
1311 } | 1267 } |
1312 | 1268 |
1313 Runnable run_after_sending_success = null; | 1269 Runnable run_after_sending_success = null; |
1314 | |
1315 ServerSessionCallback sscb = server_session.getServerSessionCallback(); | 1270 ServerSessionCallback sscb = server_session.getServerSessionCallback(); |
1316 | 1271 |
1317 if(sscb != null) { | 1272 if (sscb != null) { |
1318 run_after_sending_success = sscb.requestPtyReq(server_session, pty); | 1273 run_after_sending_success = sscb.requestPtyReq(server_session, pty); |
1319 } | 1274 } |
1320 | 1275 |
1321 if(wantReply) { | 1276 if (wantReply) { |
1322 if(run_after_sending_success != null) { | 1277 if (run_after_sending_success != null) { |
1323 tm.sendAsynchronousMessage(new PacketChannelSuccess(c.remoteID).getPayload()); | 1278 tm.sendAsynchronousMessage(new PacketChannelSuccess(c.remoteID).getPayload()); |
1324 } | 1279 } |
1325 else { | 1280 else { |
1326 tm.sendAsynchronousMessage(new PacketChannelFailure(c.remoteID).getPayload()); | 1281 tm.sendAsynchronousMessage(new PacketChannelFailure(c.remoteID).getPayload()); |
1327 } | 1282 } |
1328 } | 1283 } |
1329 | 1284 |
1330 if(run_after_sending_success != null) { | 1285 if (run_after_sending_success != null) { |
1331 runAsync(run_after_sending_success); | 1286 runAsync(run_after_sending_success); |
1332 } | 1287 } |
1333 | 1288 |
1334 return; | 1289 return; |
1335 } | 1290 } |
1336 | 1291 |
1337 if((server_session != null) && (type.equals("shell"))) { | 1292 if ((server_session != null) && (type.equals("shell"))) { |
1338 if(tr.remain() != 0) { | 1293 if (tr.remain() != 0) { |
1339 throw new IOException("Badly formatted SSH_MSG_CHANNEL_REQUEST message"); | 1294 throw new IOException("Badly formatted SSH_MSG_CHANNEL_REQUEST message"); |
1340 } | 1295 } |
1341 | 1296 |
1342 Runnable run_after_sending_success = null; | 1297 Runnable run_after_sending_success = null; |
1343 ServerSessionCallback sscb = server_session.getServerSessionCallback(); | 1298 ServerSessionCallback sscb = server_session.getServerSessionCallback(); |
1344 | 1299 |
1345 if(sscb != null) { | 1300 if (sscb != null) { |
1346 run_after_sending_success = sscb.requestShell(server_session); | 1301 run_after_sending_success = sscb.requestShell(server_session); |
1347 } | 1302 } |
1348 | 1303 |
1349 if(wantReply) { | 1304 if (wantReply) { |
1350 if(run_after_sending_success != null) { | 1305 if (run_after_sending_success != null) { |
1351 tm.sendAsynchronousMessage(new PacketChannelSuccess(c.remoteID).getPayload()); | 1306 tm.sendAsynchronousMessage(new PacketChannelSuccess(c.remoteID).getPayload()); |
1352 } | 1307 } |
1353 else { | 1308 else { |
1354 tm.sendAsynchronousMessage(new PacketChannelFailure(c.remoteID).getPayload()); | 1309 tm.sendAsynchronousMessage(new PacketChannelFailure(c.remoteID).getPayload()); |
1355 } | 1310 } |
1356 } | 1311 } |
1357 | 1312 |
1358 if(run_after_sending_success != null) { | 1313 if (run_after_sending_success != null) { |
1359 runAsync(run_after_sending_success); | 1314 runAsync(run_after_sending_success); |
1360 } | 1315 } |
1361 | 1316 |
1362 return; | 1317 return; |
1363 } | 1318 } |
1364 | 1319 |
1365 if((server_session != null) && (type.equals("exec"))) { | 1320 if ((server_session != null) && (type.equals("exec"))) { |
1366 String command = tr.readString(); | 1321 String command = tr.readString(); |
1367 | 1322 |
1368 if(tr.remain() != 0) { | 1323 if (tr.remain() != 0) { |
1369 throw new IOException("Badly formatted SSH_MSG_CHANNEL_REQUEST message"); | 1324 throw new IOException("Badly formatted SSH_MSG_CHANNEL_REQUEST message"); |
1370 } | 1325 } |
1371 | 1326 |
1372 Runnable run_after_sending_success = null; | 1327 Runnable run_after_sending_success = null; |
1373 ServerSessionCallback sscb = server_session.getServerSessionCallback(); | 1328 ServerSessionCallback sscb = server_session.getServerSessionCallback(); |
1374 | 1329 |
1375 if(sscb != null) { | 1330 if (sscb != null) { |
1376 run_after_sending_success = sscb.requestExec(server_session, command); | 1331 run_after_sending_success = sscb.requestExec(server_session, command); |
1377 } | 1332 } |
1378 | 1333 |
1379 if(wantReply) { | 1334 if (wantReply) { |
1380 if(run_after_sending_success != null) { | 1335 if (run_after_sending_success != null) { |
1381 tm.sendAsynchronousMessage(new PacketChannelSuccess(c.remoteID).getPayload()); | 1336 tm.sendAsynchronousMessage(new PacketChannelSuccess(c.remoteID).getPayload()); |
1382 } | 1337 } |
1383 else { | 1338 else { |
1384 tm.sendAsynchronousMessage(new PacketChannelFailure(c.remoteID).getPayload()); | 1339 tm.sendAsynchronousMessage(new PacketChannelFailure(c.remoteID).getPayload()); |
1385 } | 1340 } |
1386 } | 1341 } |
1387 | 1342 |
1388 if(run_after_sending_success != null) { | 1343 if (run_after_sending_success != null) { |
1389 runAsync(run_after_sending_success); | 1344 runAsync(run_after_sending_success); |
1390 } | 1345 } |
1391 | 1346 |
1392 return; | 1347 return; |
1393 } | 1348 } |
1394 | 1349 |
1395 /* We simply ignore unknown channel requests, however, if the server wants a reply, | 1350 /* We simply ignore unknown channel requests, however, if the server wants a reply, |
1396 * then we signal that we have no idea what it is about. | 1351 * then we signal that we have no idea what it is about. |
1397 */ | 1352 */ |
1398 | 1353 |
1399 if(wantReply) { | 1354 if (wantReply) { |
1400 tm.sendAsynchronousMessage(new PacketChannelFailure(c.remoteID).getPayload()); | 1355 tm.sendAsynchronousMessage(new PacketChannelFailure(c.remoteID).getPayload()); |
1401 } | 1356 } |
1402 | 1357 |
1403 log.debug("Channel request '" + type + "' is not known, ignoring it"); | 1358 log.debug("Channel request '" + type + "' is not known, ignoring it"); |
1404 } | 1359 } |
1405 | 1360 |
1406 public void msgChannelEOF(byte[] msg) throws IOException { | 1361 public void msgChannelEOF(byte[] msg) throws IOException { |
1407 if(msg.length != 5) { | 1362 if (msg.length != 5) { |
1408 throw new PacketFormatException(String.format("SSH_MSG_CHANNEL_EOF message has wrong size (%d)", msg.length)); | 1363 throw new PacketFormatException(String.format("SSH_MSG_CHANNEL_EOF message has wrong size (%d)", msg.length)); |
1409 } | 1364 } |
1410 | 1365 |
1411 int id = ((msg[1] & 0xff) << 24) | ((msg[2] & 0xff) << 16) | ((msg[3] & 0xff) << 8) | (msg[4] & 0xff); | 1366 int id = ((msg[1] & 0xff) << 24) | ((msg[2] & 0xff) << 16) | ((msg[3] & 0xff) << 8) | (msg[4] & 0xff); |
1412 | |
1413 Channel c = getChannel(id); | 1367 Channel c = getChannel(id); |
1414 | 1368 |
1415 if(c == null) { | 1369 if (c == null) { |
1416 throw new PacketTypeException("Unexpected SSH_MSG_CHANNEL_EOF message for non-existent channel " + id); | 1370 throw new PacketTypeException("Unexpected SSH_MSG_CHANNEL_EOF message for non-existent channel " + id); |
1417 } | 1371 } |
1418 | 1372 |
1419 synchronized(c) { | 1373 synchronized (c) { |
1420 c.EOF = true; | 1374 c.EOF = true; |
1421 c.notifyAll(); | 1375 c.notifyAll(); |
1422 } | 1376 } |
1423 | 1377 |
1424 log.debug("Got SSH_MSG_CHANNEL_EOF (channel " + id + ")"); | 1378 log.debug("Got SSH_MSG_CHANNEL_EOF (channel " + id + ")"); |
1425 } | 1379 } |
1426 | 1380 |
1427 public void msgChannelClose(byte[] msg) throws IOException { | 1381 public void msgChannelClose(byte[] msg) throws IOException { |
1428 if(msg.length != 5) { | 1382 if (msg.length != 5) { |
1429 throw new PacketFormatException("SSH_MSG_CHANNEL_CLOSE message has wrong size (" + msg.length + ")"); | 1383 throw new PacketFormatException("SSH_MSG_CHANNEL_CLOSE message has wrong size (" + msg.length + ")"); |
1430 } | 1384 } |
1431 | 1385 |
1432 int id = ((msg[1] & 0xff) << 24) | ((msg[2] & 0xff) << 16) | ((msg[3] & 0xff) << 8) | (msg[4] & 0xff); | 1386 int id = ((msg[1] & 0xff) << 24) | ((msg[2] & 0xff) << 16) | ((msg[3] & 0xff) << 8) | (msg[4] & 0xff); |
1433 | |
1434 Channel c = getChannel(id); | 1387 Channel c = getChannel(id); |
1435 | 1388 |
1436 if(c == null) { | 1389 if (c == null) { |
1437 throw new IOException("Unexpected SSH_MSG_CHANNEL_CLOSE message for non-existent channel " + id); | 1390 throw new IOException("Unexpected SSH_MSG_CHANNEL_CLOSE message for non-existent channel " + id); |
1438 } | 1391 } |
1439 | 1392 |
1440 synchronized(c) { | 1393 synchronized (c) { |
1441 c.EOF = true; | 1394 c.EOF = true; |
1442 c.state = Channel.STATE_CLOSED; | 1395 c.state = Channel.STATE_CLOSED; |
1443 c.setReasonClosed(new ChannelClosedException("Close requested by remote")); | 1396 c.setReasonClosed(new ChannelClosedException("Close requested by remote")); |
1444 c.closeMessageRecv = true; | 1397 c.closeMessageRecv = true; |
1445 | |
1446 removeChannel(c.localID); | 1398 removeChannel(c.localID); |
1447 | |
1448 c.notifyAll(); | 1399 c.notifyAll(); |
1449 } | 1400 } |
1450 | 1401 |
1451 log.debug("Got SSH_MSG_CHANNEL_CLOSE (channel " + id + ")"); | 1402 log.debug("Got SSH_MSG_CHANNEL_CLOSE (channel " + id + ")"); |
1452 } | 1403 } |
1453 | 1404 |
1454 public void msgChannelSuccess(byte[] msg) throws IOException { | 1405 public void msgChannelSuccess(byte[] msg) throws IOException { |
1455 if(msg.length != 5) { | 1406 if (msg.length != 5) { |
1456 throw new PacketFormatException("SSH_MSG_CHANNEL_SUCCESS message has wrong size (" + msg.length + ")"); | 1407 throw new PacketFormatException("SSH_MSG_CHANNEL_SUCCESS message has wrong size (" + msg.length + ")"); |
1457 } | 1408 } |
1458 | 1409 |
1459 int id = ((msg[1] & 0xff) << 24) | ((msg[2] & 0xff) << 16) | ((msg[3] & 0xff) << 8) | (msg[4] & 0xff); | 1410 int id = ((msg[1] & 0xff) << 24) | ((msg[2] & 0xff) << 16) | ((msg[3] & 0xff) << 8) | (msg[4] & 0xff); |
1460 | |
1461 Channel c = getChannel(id); | 1411 Channel c = getChannel(id); |
1462 | 1412 |
1463 if(c == null) { | 1413 if (c == null) { |
1464 throw new PacketTypeException("Unexpected SSH_MSG_CHANNEL_SUCCESS message for non-existent channel " + id); | 1414 throw new PacketTypeException("Unexpected SSH_MSG_CHANNEL_SUCCESS message for non-existent channel " + id); |
1465 } | 1415 } |
1466 | 1416 |
1467 synchronized(c) { | 1417 synchronized (c) { |
1468 c.successCounter++; | 1418 c.successCounter++; |
1469 c.notifyAll(); | 1419 c.notifyAll(); |
1470 } | 1420 } |
1471 | 1421 |
1472 log.debug("Got SSH_MSG_CHANNEL_SUCCESS (channel " + id + ")"); | 1422 log.debug("Got SSH_MSG_CHANNEL_SUCCESS (channel " + id + ")"); |
1473 } | 1423 } |
1474 | 1424 |
1475 public void msgChannelFailure(byte[] msg) throws IOException { | 1425 public void msgChannelFailure(byte[] msg) throws IOException { |
1476 if(msg.length != 5) { | 1426 if (msg.length != 5) { |
1477 throw new PacketFormatException(String.format("SSH_MSG_CHANNEL_FAILURE message has wrong size (%d)", msg.length)); | 1427 throw new PacketFormatException(String.format("SSH_MSG_CHANNEL_FAILURE message has wrong size (%d)", msg.length)); |
1478 } | 1428 } |
1479 | 1429 |
1480 int id = ((msg[1] & 0xff) << 24) | ((msg[2] & 0xff) << 16) | ((msg[3] & 0xff) << 8) | (msg[4] & 0xff); | 1430 int id = ((msg[1] & 0xff) << 24) | ((msg[2] & 0xff) << 16) | ((msg[3] & 0xff) << 8) | (msg[4] & 0xff); |
1481 | |
1482 Channel c = getChannel(id); | 1431 Channel c = getChannel(id); |
1483 | 1432 |
1484 if(c == null) { | 1433 if (c == null) { |
1485 throw new PacketTypeException("Unexpected SSH_MSG_CHANNEL_FAILURE message for non-existent channel " + id); | 1434 throw new PacketTypeException("Unexpected SSH_MSG_CHANNEL_FAILURE message for non-existent channel " + id); |
1486 } | 1435 } |
1487 | 1436 |
1488 synchronized(c) { | 1437 synchronized (c) { |
1489 c.failedCounter++; | 1438 c.failedCounter++; |
1490 c.notifyAll(); | 1439 c.notifyAll(); |
1491 } | 1440 } |
1492 | 1441 |
1493 log.debug("Got SSH_MSG_CHANNEL_FAILURE (channel " + id + ")"); | 1442 log.debug("Got SSH_MSG_CHANNEL_FAILURE (channel " + id + ")"); |
1494 } | 1443 } |
1495 | 1444 |
1496 public void msgChannelOpenConfirmation(byte[] msg) throws IOException { | 1445 public void msgChannelOpenConfirmation(byte[] msg) throws IOException { |
1497 PacketChannelOpenConfirmation sm = new PacketChannelOpenConfirmation(msg); | 1446 PacketChannelOpenConfirmation sm = new PacketChannelOpenConfirmation(msg); |
1498 | |
1499 Channel c = getChannel(sm.getRecipientChannelID()); | 1447 Channel c = getChannel(sm.getRecipientChannelID()); |
1500 | 1448 |
1501 if(c == null) { | 1449 if (c == null) { |
1502 throw new PacketTypeException("Unexpected SSH_MSG_CHANNEL_OPEN_CONFIRMATION message for non-existent channel " | 1450 throw new PacketTypeException("Unexpected SSH_MSG_CHANNEL_OPEN_CONFIRMATION message for non-existent channel " |
1503 + sm.getRecipientChannelID()); | 1451 + sm.getRecipientChannelID()); |
1504 } | 1452 } |
1505 | 1453 |
1506 synchronized(c) { | 1454 synchronized (c) { |
1507 if(c.state != Channel.STATE_OPENING) { | 1455 if (c.state != Channel.STATE_OPENING) { |
1508 throw new PacketTypeException("Unexpected SSH_MSG_CHANNEL_OPEN_CONFIRMATION message for channel " | 1456 throw new PacketTypeException("Unexpected SSH_MSG_CHANNEL_OPEN_CONFIRMATION message for channel " |
1509 + sm.getRecipientChannelID()); | 1457 + sm.getRecipientChannelID()); |
1510 } | 1458 } |
1511 | 1459 |
1512 c.remoteID = sm.getSenderChannelID(); | 1460 c.remoteID = sm.getSenderChannelID(); |
1513 c.remoteWindow = sm.getInitialWindowSize() & 0xFFFFffffL; /* convert UINT32 to long */ | 1461 c.remoteWindow = sm.getInitialWindowSize() & 0xFFFFffffL; /* convert UINT32 to long */ |
1514 c.remoteMaxPacketSize = sm.getMaxPacketSize(); | 1462 c.remoteMaxPacketSize = sm.getMaxPacketSize(); |
1515 c.state = Channel.STATE_OPEN; | 1463 c.state = Channel.STATE_OPEN; |
1516 c.notifyAll(); | 1464 c.notifyAll(); |
1517 } | 1465 } |
1518 | 1466 |
1519 log.debug("Got SSH_MSG_CHANNEL_OPEN_CONFIRMATION (channel " + sm.getRecipientChannelID() + " / remote: " | 1467 log.debug("Got SSH_MSG_CHANNEL_OPEN_CONFIRMATION (channel " + sm.getRecipientChannelID() + " / remote: " |
1520 + sm.getSenderChannelID() + ")"); | 1468 + sm.getSenderChannelID() + ")"); |
1521 } | 1469 } |
1522 | 1470 |
1523 public void msgChannelOpenFailure(byte[] msg) throws IOException { | 1471 public void msgChannelOpenFailure(byte[] msg) throws IOException { |
1524 if(msg.length < 5) { | 1472 if (msg.length < 5) { |
1525 throw new PacketFormatException(String.format("SSH_MSG_CHANNEL_OPEN_FAILURE message has wrong size (%d)", msg.length)); | 1473 throw new PacketFormatException(String.format("SSH_MSG_CHANNEL_OPEN_FAILURE message has wrong size (%d)", msg.length)); |
1526 } | 1474 } |
1527 | 1475 |
1528 TypesReader tr = new TypesReader(msg); | 1476 TypesReader tr = new TypesReader(msg); |
1529 | |
1530 tr.readByte(); // skip packet type | 1477 tr.readByte(); // skip packet type |
1531 int id = tr.readUINT32(); /* sender channel */ | 1478 int id = tr.readUINT32(); /* sender channel */ |
1532 | |
1533 Channel c = getChannel(id); | 1479 Channel c = getChannel(id); |
1534 | 1480 |
1535 if(c == null) { | 1481 if (c == null) { |
1536 throw new PacketTypeException("Unexpected SSH_MSG_CHANNEL_OPEN_FAILURE message for non-existent channel " + id); | 1482 throw new PacketTypeException("Unexpected SSH_MSG_CHANNEL_OPEN_FAILURE message for non-existent channel " + id); |
1537 } | 1483 } |
1538 | 1484 |
1539 int reasonCode = tr.readUINT32(); | 1485 int reasonCode = tr.readUINT32(); |
1540 String description = tr.readString("UTF-8"); | 1486 String description = tr.readString("UTF-8"); |
1541 | |
1542 String reasonCodeSymbolicName; | 1487 String reasonCodeSymbolicName; |
1543 | 1488 |
1544 switch(reasonCode) { | 1489 switch (reasonCode) { |
1545 case 1: | 1490 case 1: |
1546 reasonCodeSymbolicName = "SSH_OPEN_ADMINISTRATIVELY_PROHIBITED"; | 1491 reasonCodeSymbolicName = "SSH_OPEN_ADMINISTRATIVELY_PROHIBITED"; |
1547 break; | 1492 break; |
1493 | |
1548 case 2: | 1494 case 2: |
1549 reasonCodeSymbolicName = "SSH_OPEN_CONNECT_FAILED"; | 1495 reasonCodeSymbolicName = "SSH_OPEN_CONNECT_FAILED"; |
1550 break; | 1496 break; |
1497 | |
1551 case 3: | 1498 case 3: |
1552 reasonCodeSymbolicName = "SSH_OPEN_UNKNOWN_CHANNEL_TYPE"; | 1499 reasonCodeSymbolicName = "SSH_OPEN_UNKNOWN_CHANNEL_TYPE"; |
1553 break; | 1500 break; |
1501 | |
1554 case 4: | 1502 case 4: |
1555 reasonCodeSymbolicName = "SSH_OPEN_RESOURCE_SHORTAGE"; | 1503 reasonCodeSymbolicName = "SSH_OPEN_RESOURCE_SHORTAGE"; |
1556 break; | 1504 break; |
1505 | |
1557 default: | 1506 default: |
1558 reasonCodeSymbolicName = "UNKNOWN REASON CODE (" + reasonCode + ")"; | 1507 reasonCodeSymbolicName = "UNKNOWN REASON CODE (" + reasonCode + ")"; |
1559 } | 1508 } |
1560 | 1509 |
1561 StringBuilder descriptionBuffer = new StringBuilder(); | 1510 StringBuilder descriptionBuffer = new StringBuilder(); |
1562 descriptionBuffer.append(description); | 1511 descriptionBuffer.append(description); |
1563 | 1512 |
1564 for(int i = 0; i < descriptionBuffer.length(); i++) { | 1513 for (int i = 0; i < descriptionBuffer.length(); i++) { |
1565 char cc = descriptionBuffer.charAt(i); | 1514 char cc = descriptionBuffer.charAt(i); |
1566 | 1515 |
1567 if((cc >= 32) && (cc <= 126)) { | 1516 if ((cc >= 32) && (cc <= 126)) { |
1568 continue; | 1517 continue; |
1569 } | 1518 } |
1519 | |
1570 descriptionBuffer.setCharAt(i, '\uFFFD'); | 1520 descriptionBuffer.setCharAt(i, '\uFFFD'); |
1571 } | 1521 } |
1572 | 1522 |
1573 synchronized(c) { | 1523 synchronized (c) { |
1574 c.EOF = true; | 1524 c.EOF = true; |
1575 c.state = Channel.STATE_CLOSED; | 1525 c.state = Channel.STATE_CLOSED; |
1576 c.setReasonClosed(new ChannelClosedException(String.format("The server refused to open the channel (%s, '%s')", | 1526 c.setReasonClosed(new ChannelClosedException(String.format("The server refused to open the channel (%s, '%s')", |
1577 reasonCodeSymbolicName, descriptionBuffer.toString()))); | 1527 reasonCodeSymbolicName, descriptionBuffer.toString()))); |
1578 c.notifyAll(); | 1528 c.notifyAll(); |
1579 } | 1529 } |
1580 | 1530 |
1581 log.debug("Got SSH_MSG_CHANNEL_OPEN_FAILURE (channel " + id + ")"); | 1531 log.debug("Got SSH_MSG_CHANNEL_OPEN_FAILURE (channel " + id + ")"); |
1582 } | 1532 } |
1583 | 1533 |
1584 public void msgGlobalRequest(byte[] msg) throws IOException { | 1534 public void msgGlobalRequest(byte[] msg) throws IOException { |
1585 /* Currently we do not support any kind of global request */ | 1535 /* Currently we do not support any kind of global request */ |
1586 | |
1587 TypesReader tr = new TypesReader(msg); | 1536 TypesReader tr = new TypesReader(msg); |
1588 | |
1589 tr.readByte(); // skip packet type | 1537 tr.readByte(); // skip packet type |
1590 String requestName = tr.readString(); | 1538 String requestName = tr.readString(); |
1591 boolean wantReply = tr.readBoolean(); | 1539 boolean wantReply = tr.readBoolean(); |
1592 | 1540 |
1593 if(wantReply) { | 1541 if (wantReply) { |
1594 byte[] reply_failure = new byte[1]; | 1542 byte[] reply_failure = new byte[1]; |
1595 reply_failure[0] = Packets.SSH_MSG_REQUEST_FAILURE; | 1543 reply_failure[0] = Packets.SSH_MSG_REQUEST_FAILURE; |
1596 | |
1597 tm.sendAsynchronousMessage(reply_failure); | 1544 tm.sendAsynchronousMessage(reply_failure); |
1598 } | 1545 } |
1599 | 1546 |
1600 /* We do not clean up the requestName String - that is OK for debug */ | 1547 /* We do not clean up the requestName String - that is OK for debug */ |
1601 | |
1602 log.debug("Got SSH_MSG_GLOBAL_REQUEST (" + requestName + ")"); | 1548 log.debug("Got SSH_MSG_GLOBAL_REQUEST (" + requestName + ")"); |
1603 } | 1549 } |
1604 | 1550 |
1605 public void msgGlobalSuccess() throws IOException { | 1551 public void msgGlobalSuccess() throws IOException { |
1606 synchronized(channels) { | 1552 synchronized (channels) { |
1607 globalSuccessCounter++; | 1553 globalSuccessCounter++; |
1608 channels.notifyAll(); | 1554 channels.notifyAll(); |
1609 } | 1555 } |
1610 | 1556 |
1611 log.debug("Got SSH_MSG_REQUEST_SUCCESS"); | 1557 log.debug("Got SSH_MSG_REQUEST_SUCCESS"); |
1612 } | 1558 } |
1613 | 1559 |
1614 public void msgGlobalFailure() throws IOException { | 1560 public void msgGlobalFailure() throws IOException { |
1615 synchronized(channels) { | 1561 synchronized (channels) { |
1616 globalFailedCounter++; | 1562 globalFailedCounter++; |
1617 channels.notifyAll(); | 1563 channels.notifyAll(); |
1618 } | 1564 } |
1619 | 1565 |
1620 log.debug("Got SSH_MSG_REQUEST_FAILURE"); | 1566 log.debug("Got SSH_MSG_REQUEST_FAILURE"); |
1621 } | 1567 } |
1622 | 1568 |
1623 public void handleFailure(final IOException failure) { | 1569 public void handleFailure(final IOException failure) { |
1624 log.debug("HandleMessage: got shutdown"); | 1570 log.debug("HandleMessage: got shutdown"); |
1625 | 1571 |
1626 synchronized(listenerThreads) { | 1572 synchronized (listenerThreads) { |
1627 for(IChannelWorkerThread lat : listenerThreads) { | 1573 for (IChannelWorkerThread lat : listenerThreads) { |
1628 lat.stopWorking(); | 1574 lat.stopWorking(); |
1629 } | 1575 } |
1576 | |
1630 listenerThreadsAllowed = false; | 1577 listenerThreadsAllowed = false; |
1631 } | 1578 } |
1632 | 1579 |
1633 synchronized(channels) { | 1580 synchronized (channels) { |
1634 shutdown = true; | 1581 shutdown = true; |
1635 | 1582 |
1636 for(Channel c : channels) { | 1583 for (Channel c : channels) { |
1637 synchronized(c) { | 1584 synchronized (c) { |
1638 c.EOF = true; | 1585 c.EOF = true; |
1639 c.state = Channel.STATE_CLOSED; | 1586 c.state = Channel.STATE_CLOSED; |
1640 c.setReasonClosed(failure); | 1587 c.setReasonClosed(failure); |
1641 c.closeMessageRecv = true; | 1588 c.closeMessageRecv = true; |
1642 c.notifyAll(); | 1589 c.notifyAll(); |
1643 } | 1590 } |
1644 } | 1591 } |
1592 | |
1645 channels.clear(); | 1593 channels.clear(); |
1646 channels.notifyAll(); /* Notify global response waiters */ | 1594 channels.notifyAll(); /* Notify global response waiters */ |
1647 } | 1595 } |
1648 } | 1596 } |
1649 | 1597 |
1650 public void handleMessage(byte[] msg) throws IOException { | 1598 public void handleMessage(byte[] msg) throws IOException { |
1651 switch(msg[0]) { | 1599 switch (msg[0]) { |
1652 case Packets.SSH_MSG_CHANNEL_OPEN_CONFIRMATION: | 1600 case Packets.SSH_MSG_CHANNEL_OPEN_CONFIRMATION: |
1653 msgChannelOpenConfirmation(msg); | 1601 msgChannelOpenConfirmation(msg); |
1654 break; | 1602 break; |
1603 | |
1655 case Packets.SSH_MSG_CHANNEL_WINDOW_ADJUST: | 1604 case Packets.SSH_MSG_CHANNEL_WINDOW_ADJUST: |
1656 msgChannelWindowAdjust(msg); | 1605 msgChannelWindowAdjust(msg); |
1657 break; | 1606 break; |
1607 | |
1658 case Packets.SSH_MSG_CHANNEL_DATA: | 1608 case Packets.SSH_MSG_CHANNEL_DATA: |
1659 msgChannelData(msg); | 1609 msgChannelData(msg); |
1660 break; | 1610 break; |
1611 | |
1661 case Packets.SSH_MSG_CHANNEL_EXTENDED_DATA: | 1612 case Packets.SSH_MSG_CHANNEL_EXTENDED_DATA: |
1662 msgChannelExtendedData(msg); | 1613 msgChannelExtendedData(msg); |
1663 break; | 1614 break; |
1615 | |
1664 case Packets.SSH_MSG_CHANNEL_REQUEST: | 1616 case Packets.SSH_MSG_CHANNEL_REQUEST: |
1665 msgChannelRequest(msg); | 1617 msgChannelRequest(msg); |
1666 break; | 1618 break; |
1619 | |
1667 case Packets.SSH_MSG_CHANNEL_EOF: | 1620 case Packets.SSH_MSG_CHANNEL_EOF: |
1668 msgChannelEOF(msg); | 1621 msgChannelEOF(msg); |
1669 break; | 1622 break; |
1623 | |
1670 case Packets.SSH_MSG_CHANNEL_OPEN: | 1624 case Packets.SSH_MSG_CHANNEL_OPEN: |
1671 msgChannelOpen(msg); | 1625 msgChannelOpen(msg); |
1672 break; | 1626 break; |
1627 | |
1673 case Packets.SSH_MSG_CHANNEL_CLOSE: | 1628 case Packets.SSH_MSG_CHANNEL_CLOSE: |
1674 msgChannelClose(msg); | 1629 msgChannelClose(msg); |
1675 break; | 1630 break; |
1631 | |
1676 case Packets.SSH_MSG_CHANNEL_SUCCESS: | 1632 case Packets.SSH_MSG_CHANNEL_SUCCESS: |
1677 msgChannelSuccess(msg); | 1633 msgChannelSuccess(msg); |
1678 break; | 1634 break; |
1635 | |
1679 case Packets.SSH_MSG_CHANNEL_FAILURE: | 1636 case Packets.SSH_MSG_CHANNEL_FAILURE: |
1680 msgChannelFailure(msg); | 1637 msgChannelFailure(msg); |
1681 break; | 1638 break; |
1639 | |
1682 case Packets.SSH_MSG_CHANNEL_OPEN_FAILURE: | 1640 case Packets.SSH_MSG_CHANNEL_OPEN_FAILURE: |
1683 msgChannelOpenFailure(msg); | 1641 msgChannelOpenFailure(msg); |
1684 break; | 1642 break; |
1643 | |
1685 case Packets.SSH_MSG_GLOBAL_REQUEST: | 1644 case Packets.SSH_MSG_GLOBAL_REQUEST: |
1686 msgGlobalRequest(msg); | 1645 msgGlobalRequest(msg); |
1687 break; | 1646 break; |
1647 | |
1688 case Packets.SSH_MSG_REQUEST_SUCCESS: | 1648 case Packets.SSH_MSG_REQUEST_SUCCESS: |
1689 msgGlobalSuccess(); | 1649 msgGlobalSuccess(); |
1690 break; | 1650 break; |
1651 | |
1691 case Packets.SSH_MSG_REQUEST_FAILURE: | 1652 case Packets.SSH_MSG_REQUEST_FAILURE: |
1692 msgGlobalFailure(); | 1653 msgGlobalFailure(); |
1693 break; | 1654 break; |
1655 | |
1694 default: | 1656 default: |
1695 throw new PacketTypeException(msg[0]); | 1657 throw new PacketTypeException(msg[0]); |
1696 } | 1658 } |
1697 } | 1659 } |
1698 } | 1660 } |