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 }