1 /*
2 * SSHTools - Java SSH2 API
3 *
4 * Copyright (C) 2002-2003 Lee David Painter and Contributors.
5 *
6 * Contributions made by:
7 *
8 * Brett Smith
9 * Richard Pernavas
10 * Erwin Bolwidt
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
25 */
26 package com.sshtools.j2ssh.connection;
27
28 import com.sshtools.j2ssh.SshException;
29 import com.sshtools.j2ssh.transport.AsyncService;
30 import com.sshtools.j2ssh.transport.MessageStoreEOFException;
31 import com.sshtools.j2ssh.transport.ServiceState;
32 import com.sshtools.j2ssh.transport.SshMessage;
33 import com.sshtools.j2ssh.transport.TransportProtocolState;
34
35 import org.apache.commons.logging.Log;
36 import org.apache.commons.logging.LogFactory;
37
38 import java.io.IOException;
39
40 import java.util.HashMap;
41 import java.util.concurrent.ConcurrentHashMap;
42 import java.util.HashSet;
43 import java.util.Iterator;
44 import java.util.Map;
45
46
47 /**
48 *
49 *
50 * @author $author$
51 * @version $Revision: 1.68 $
52 */
53 public class ConnectionProtocol extends AsyncService {
54 private static Log log = LogFactory.getLog(ConnectionProtocol.class);
55 private HashSet reusableChannels = new HashSet();
56 private Map activeChannels = new ConcurrentHashMap();
57 private Map allowedChannels = new HashMap();
58 private Map globalRequests = new HashMap();
59 private long nextChannelId = 0;
60
61 /**
62 * Creates a new ConnectionProtocol object.
63 */
64 public ConnectionProtocol() {
65 super("ssh-connection");
66 }
67
68 /**
69 *
70 *
71 * @param channelName
72 * @param cf
73 *
74 * @throws IOException
75 */
76 public void addChannelFactory(String channelName, ChannelFactory cf)
77 throws IOException {
78 allowedChannels.put(channelName, cf);
79 }
80
81 /**
82 *
83 *
84 * @param channelName
85 */
86 public void removeChannelFactory(String channelName) {
87 allowedChannels.remove(channelName);
88 }
89
90 /**
91 *
92 *
93 * @param channelName
94 *
95 * @return
96 */
97 public boolean containsChannelFactory(String channelName) {
98 return allowedChannels.containsKey(channelName);
99 }
100
101 /**
102 *
103 *
104 * @param requestName
105 * @param handler
106 */
107 public void allowGlobalRequest(String requestName,
108 GlobalRequestHandler handler) {
109 globalRequests.put(requestName, handler);
110 }
111
112 /**
113 *
114 *
115 * @param channel
116 *
117 * @return
118 *
119 * @throws IOException
120 */
121 public synchronized boolean openChannel(Channel channel)
122 throws IOException {
123 return openChannel(channel, null);
124 }
125
126 /**
127 *
128 *
129 * @return
130 */
131 public boolean isConnected() {
132 return ((transport.getState().getValue() == TransportProtocolState.CONNECTED) ||
133 (transport.getState().getValue() == TransportProtocolState.PERFORMING_KEYEXCHANGE)) &&
134 (getState().getValue() == ServiceState.SERVICE_STARTED);
135 }
136
137 private Long getChannelId() {
138 // synchronized (activeChannels) {
139 if (reusableChannels.size() <= 0) {
140 return new Long(nextChannelId++);
141 } else {
142 return (Long) reusableChannels.iterator().next();
143 }
144 //}
145 }
146
147 /**
148 *
149 *
150 * @param channel
151 * @param eventListener
152 *
153 * @return
154 *
155 * @throws IOException
156 * @throws SshException
157 */
158 public synchronized boolean openChannel(Channel channel,
159 ChannelEventListener eventListener) throws IOException {
160 //synchronized (activeChannels) {
161 Long channelId = getChannelId();
162
163 // Create the message
164 SshMsgChannelOpen msg = new SshMsgChannelOpen(channel.getChannelType(),
165 channelId.longValue(),
166 channel.getLocalWindow().getWindowSpace(),
167 channel.getLocalPacketSize(), channel.getChannelOpenData());
168
169 // Send the message
170 transport.sendMessage(msg, this);
171
172 // Wait for the next message to confirm the open channel (or not)
173 int[] messageIdFilter = new int[2];
174 messageIdFilter[0] = SshMsgChannelOpenConfirmation.SSH_MSG_CHANNEL_OPEN_CONFIRMATION;
175 messageIdFilter[1] = SshMsgChannelOpenFailure.SSH_MSG_CHANNEL_OPEN_FAILURE;
176
177 try {
178 SshMessage result = messageStore.getMessage(messageIdFilter);
179
180 if (result.getMessageId() == SshMsgChannelOpenConfirmation.SSH_MSG_CHANNEL_OPEN_CONFIRMATION) {
181 SshMsgChannelOpenConfirmation conf = (SshMsgChannelOpenConfirmation) result;
182 activeChannels.put(channelId, channel);
183 log.debug("Initiating channel");
184 channel.init(this, channelId.longValue(),
185 conf.getSenderChannel(), conf.getInitialWindowSize(),
186 conf.getMaximumPacketSize(), eventListener);
187 channel.open();
188 log.info("Channel " +
189 String.valueOf(channel.getLocalChannelId()) +
190 " is open [" + channel.getName() + "]");
191
192 return true;
193 } else {
194 // Make sure the channels state is closed
195 channel.getState().setValue(ChannelState.CHANNEL_CLOSED);
196
197 return false;
198 }
199 } catch (MessageStoreEOFException mse) {
200 throw new IOException(mse.getMessage());
201 } catch (InterruptedException ex) {
202 throw new SshException(
203 "The thread was interrupted whilst waiting for a connection protocol message");
204 }
205 //}
206 }
207
208 /**
209 *
210 */
211 protected synchronized void onStop() {
212 log.info("Closing all active channels");
213 // synchronized (activeChannels) {
214 log.info("thread has "+activeChannels.values().size()+" active channels to stop");
215 try {
216 Channel channel;
217
218 for (Iterator x = activeChannels.values().iterator(); x.hasNext();) {
219 channel = (Channel) x.next();
220
221 if (channel != null) {
222 if (log.isDebugEnabled()) {
223 log.debug("Closing " + channel.getName() + " id=" +
224 String.valueOf(channel.getLocalChannelId()));
225 }
226
227 channel.close();
228 }
229 }
230 } catch (Throwable t) {
231 log.error("Unable to close all channels: "+t.getMessage(),t);
232 }
233
234 activeChannels.clear();
235 // }
236 }
237
238 /**
239 *
240 *
241 * @param channel
242 * @param data
243 *
244 * @throws IOException
245 */
246 public synchronized void sendChannelData(Channel channel, byte[] data)
247 throws IOException {
248 synchronized (channel.getState()) {
249 if (log.isDebugEnabled()) {
250 log.debug("Sending " + String.valueOf(data.length) +
251 " bytes for channel id " +
252 String.valueOf(channel.getLocalChannelId()));
253 }
254
255 int sent = 0;
256 int block;
257 int remaining;
258 long max;
259 byte[] buffer;
260 ChannelDataWindow window = channel.getRemoteWindow();
261
262 while (sent < data.length) {
263 remaining = data.length - sent;
264 max = ((window.getWindowSpace() < channel.getRemotePacketSize()) &&
265 (window.getWindowSpace() > 0)) ? window.getWindowSpace()
266 : channel.getRemotePacketSize();
267 block = (max < remaining) ? (int) max : remaining;
268 channel.remoteWindow.consumeWindowSpace(block);
269 buffer = new byte[block];
270 System.arraycopy(data, sent, buffer, 0, block);
271
272 SshMsgChannelData msg = new SshMsgChannelData(channel.getRemoteChannelId(),
273 buffer);
274 transport.sendMessage(msg, this);
275
276 /* if (type != null) {
277 channel.sendChannelExtData(type.intValue(), buffer);
278 } else {
279 channel.sendChannelData(buffer);
280 }*/
281 sent += block;
282 }
283 }
284 }
285
286 /**
287 *
288 *
289 * @param channel
290 *
291 * @throws IOException
292 */
293 public void sendChannelEOF(Channel channel) throws IOException {
294 //synchronized (activeChannels) {
295 if (!activeChannels.containsValue(channel)) {
296 throw new IOException(
297 "Attempt to send EOF for a non existent channel " +
298 String.valueOf(channel.getLocalChannelId()));
299 }
300
301 log.info("Local computer has set channel " +
302 String.valueOf(channel.getLocalChannelId()) + " to EOF [" +
303 channel.getName() + "]");
304
305 SshMsgChannelEOF msg = new SshMsgChannelEOF(channel.getRemoteChannelId());
306 transport.sendMessage(msg, this);
307 // }
308 }
309
310 /**
311 *
312 *
313 * @param channel
314 * @param extendedType
315 * @param data
316 *
317 * @throws IOException
318 */
319 public synchronized void sendChannelExtData(Channel channel,
320 int extendedType, byte[] data) throws IOException {
321 channel.getRemoteWindow().consumeWindowSpace(data.length);
322
323 int sent = 0;
324 int block;
325 int remaining;
326 long max;
327 byte[] buffer;
328 ChannelDataWindow window = channel.getRemoteWindow();
329
330 while (sent < data.length) {
331 remaining = data.length - sent;
332 max = ((window.getWindowSpace() < channel.getRemotePacketSize()) &&
333 (window.getWindowSpace() > 0)) ? window.getWindowSpace()
334 : channel.getRemotePacketSize();
335 block = (max < remaining) ? (int) max : remaining;
336 channel.remoteWindow.consumeWindowSpace(block);
337 buffer = new byte[block];
338 System.arraycopy(data, sent, buffer, 0, block);
339
340 SshMsgChannelExtendedData msg = new SshMsgChannelExtendedData(channel.getRemoteChannelId(),
341 extendedType, buffer);
342 transport.sendMessage(msg, this);
343
344 /* if (type != null) {
345 channel.sendChannelExtData(type.intValue(), buffer);
346 } else {
347 channel.sendChannelData(buffer);
348 }*/
349 sent += block;
350 }
351 }
352
353 /**
354 *
355 *
356 * @param channel
357 * @param requestType
358 * @param wantReply
359 * @param requestData
360 *
361 * @return
362 *
363 * @throws IOException
364 * @throws SshException
365 */
366 public synchronized boolean sendChannelRequest(Channel channel,
367 String requestType, boolean wantReply, byte[] requestData)
368 throws IOException {
369 boolean success = true;
370 log.info("Sending " + requestType + " request for the " +
371 channel.getChannelType() + " channel");
372
373 SshMsgChannelRequest msg = new SshMsgChannelRequest(channel.getRemoteChannelId(),
374 requestType, wantReply, requestData);
375 transport.sendMessage(msg, this);
376
377 // If the user requests a reply then wait for the message and return result
378 if (wantReply) {
379 // Set up our message filter
380 int[] messageIdFilter = new int[2];
381
382 messageIdFilter[0] = SshMsgChannelSuccess.SSH_MSG_CHANNEL_SUCCESS;
383 messageIdFilter[1] = SshMsgChannelFailure.SSH_MSG_CHANNEL_FAILURE;
384
385 log.info("Waiting for channel request reply");
386
387 try {
388 // Wait for either success or failure
389 SshMessage reply = messageStore.getMessage(messageIdFilter);
390
391 switch (reply.getMessageId()) {
392 case SshMsgChannelSuccess.SSH_MSG_CHANNEL_SUCCESS: {
393 log.info("Channel request succeeded");
394 success = true;
395
396 break;
397 }
398
399 case SshMsgChannelFailure.SSH_MSG_CHANNEL_FAILURE: {
400 log.info("Channel request failed");
401 success = false;
402
403 break;
404 }
405 }
406 } catch (InterruptedException ex) {
407 throw new SshException(
408 "The thread was interrupted whilst waiting for a connection protocol message");
409 }
410 }
411
412 return success;
413 }
414
415 /**
416 *
417 *
418 * @param channel
419 *
420 * @throws IOException
421 */
422 public void sendChannelRequestFailure(Channel channel)
423 throws IOException {
424 SshMsgChannelFailure msg = new SshMsgChannelFailure(channel.getRemoteChannelId());
425 transport.sendMessage(msg, this);
426 }
427
428 /**
429 *
430 *
431 * @param channel
432 *
433 * @throws IOException
434 */
435 public void sendChannelRequestSuccess(Channel channel)
436 throws IOException {
437 SshMsgChannelSuccess msg = new SshMsgChannelSuccess(channel.getRemoteChannelId());
438 transport.sendMessage(msg, this);
439 }
440
441 /**
442 *
443 *
444 * @param channel
445 * @param bytesToAdd
446 *
447 * @throws IOException
448 */
449 public void sendChannelWindowAdjust(Channel channel, long bytesToAdd)
450 throws IOException {
451 log.debug("Increasing window size by " + String.valueOf(bytesToAdd) +
452 " bytes");
453
454 SshMsgChannelWindowAdjust msg = new SshMsgChannelWindowAdjust(channel.getRemoteChannelId(),
455 bytesToAdd);
456 transport.sendMessage(msg, this);
457 }
458
459 /**
460 *
461 *
462 * @param requestName
463 * @param wantReply
464 * @param requestData
465 *
466 * @return
467 *
468 * @throws IOException
469 * @throws SshException
470 */
471 public synchronized byte[] sendGlobalRequest(String requestName,
472 boolean wantReply, byte[] requestData) throws IOException {
473 boolean success = true;
474 SshMsgGlobalRequest msg = new SshMsgGlobalRequest(requestName, true,
475 requestData);
476 transport.sendMessage(msg, this);
477
478 if (wantReply) {
479 // Set up our message filter
480 int[] messageIdFilter = new int[2];
481 messageIdFilter[0] = SshMsgRequestSuccess.SSH_MSG_REQUEST_SUCCESS;
482 messageIdFilter[1] = SshMsgRequestFailure.SSH_MSG_REQUEST_FAILURE;
483 log.debug("Waiting for global request reply");
484
485 try {
486 // Wait for either success or failure
487 SshMessage reply = messageStore.getMessage(messageIdFilter);
488
489 switch (reply.getMessageId()) {
490 case SshMsgRequestSuccess.SSH_MSG_REQUEST_SUCCESS: {
491 log.debug("Global request succeeded");
492
493 return ((SshMsgRequestSuccess) reply).getRequestData();
494 }
495
496 case SshMsgRequestFailure.SSH_MSG_REQUEST_FAILURE: {
497 log.debug("Global request failed");
498 throw new SshException("The request failed");
499 }
500 }
501 } catch (InterruptedException ex) {
502 throw new SshException(
503 "The thread was interrupted whilst waiting for a connection protocol message");
504 }
505 }
506
507 return null;
508 }
509
510 /**
511 *
512 *
513 * @return
514 */
515 protected int[] getAsyncMessageFilter() {
516 int[] messageFilter = new int[10];
517 messageFilter[0] = SshMsgGlobalRequest.SSH_MSG_GLOBAL_REQUEST;
518 messageFilter[3] = SshMsgChannelOpen.SSH_MSG_CHANNEL_OPEN;
519 messageFilter[4] = SshMsgChannelClose.SSH_MSG_CHANNEL_CLOSE;
520 messageFilter[5] = SshMsgChannelEOF.SSH_MSG_CHANNEL_EOF;
521 messageFilter[6] = SshMsgChannelExtendedData.SSH_MSG_CHANNEL_EXTENDED_DATA;
522 messageFilter[7] = SshMsgChannelData.SSH_MSG_CHANNEL_DATA;
523 messageFilter[8] = SshMsgChannelRequest.SSH_MSG_CHANNEL_REQUEST;
524 messageFilter[9] = SshMsgChannelWindowAdjust.SSH_MSG_CHANNEL_WINDOW_ADJUST;
525
526 return messageFilter;
527 }
528
529 /**
530 *
531 *
532 * @param channel
533 *
534 * @throws IOException
535 */
536 protected void closeChannel(Channel channel) throws IOException {
537 SshMsgChannelClose msg = new SshMsgChannelClose(channel.getRemoteChannelId());
538 log.info("Local computer has closed channel " +
539 String.valueOf(channel.getLocalChannelId()) + "[" +
540 channel.getName() + "]");
541 transport.sendMessage(msg, this);
542 }
543
544 /**
545 *
546 *
547 * @param requestName
548 * @param wantReply
549 * @param requestData
550 *
551 * @throws IOException
552 */
553 protected void onGlobalRequest(String requestName, boolean wantReply,
554 byte[] requestData) throws IOException {
555 log.debug("Processing " + requestName + " global request");
556
557 if (!globalRequests.containsKey(requestName)) {
558 sendGlobalRequestFailure();
559 } else {
560 GlobalRequestHandler handler = (GlobalRequestHandler) globalRequests.get(requestName);
561 GlobalRequestResponse response = handler.processGlobalRequest(requestName,
562 requestData);
563
564 if (wantReply) {
565 if (response.hasSucceeded()) {
566 sendGlobalRequestSuccess(response.getResponseData());
567 } else {
568 sendGlobalRequestFailure();
569 }
570 }
571 }
572 }
573
574 /**
575 *
576 *
577 * @param msg
578 *
579 * @throws IOException
580 */
581 protected void onMessageReceived(SshMessage msg) throws IOException {
582 // Route the message to the correct handling function
583 switch (msg.getMessageId()) {
584 case SshMsgGlobalRequest.SSH_MSG_GLOBAL_REQUEST: {
585 onMsgGlobalRequest((SshMsgGlobalRequest) msg);
586
587 break;
588 }
589
590 case SshMsgChannelOpen.SSH_MSG_CHANNEL_OPEN: {
591 onMsgChannelOpen((SshMsgChannelOpen) msg);
592
593 break;
594 }
595
596 case SshMsgChannelClose.SSH_MSG_CHANNEL_CLOSE: {
597 onMsgChannelClose((SshMsgChannelClose) msg);
598
599 break;
600 }
601
602 case SshMsgChannelEOF.SSH_MSG_CHANNEL_EOF: {
603 onMsgChannelEOF((SshMsgChannelEOF) msg);
604
605 break;
606 }
607
608 case SshMsgChannelData.SSH_MSG_CHANNEL_DATA: {
609 onMsgChannelData((SshMsgChannelData) msg);
610
611 break;
612 }
613
614 case SshMsgChannelExtendedData.SSH_MSG_CHANNEL_EXTENDED_DATA: {
615 onMsgChannelExtendedData((SshMsgChannelExtendedData) msg);
616
617 break;
618 }
619
620 case SshMsgChannelRequest.SSH_MSG_CHANNEL_REQUEST: {
621 onMsgChannelRequest((SshMsgChannelRequest) msg);
622
623 break;
624 }
625
626 case SshMsgChannelWindowAdjust.SSH_MSG_CHANNEL_WINDOW_ADJUST: {
627 onMsgChannelWindowAdjust((SshMsgChannelWindowAdjust) msg);
628
629 break;
630 }
631
632 default: {
633 // If we never registered it why are we getting it?
634 log.debug("Message not handled");
635 throw new IOException("Unregistered message received!");
636 }
637 }
638 }
639
640 /**
641 *
642 */
643 protected void onServiceAccept() {
644 }
645
646 /**
647 *
648 *
649 * @param startMode
650 *
651 * @throws IOException
652 */
653 protected void onServiceInit(int startMode) throws IOException {
654 log.info("Registering connection protocol messages");
655 messageStore.registerMessage(SshMsgChannelOpenConfirmation.SSH_MSG_CHANNEL_OPEN_CONFIRMATION,
656 SshMsgChannelOpenConfirmation.class);
657 messageStore.registerMessage(SshMsgChannelOpenFailure.SSH_MSG_CHANNEL_OPEN_FAILURE,
658 SshMsgChannelOpenFailure.class);
659 messageStore.registerMessage(SshMsgChannelOpen.SSH_MSG_CHANNEL_OPEN,
660 SshMsgChannelOpen.class);
661 messageStore.registerMessage(SshMsgChannelClose.SSH_MSG_CHANNEL_CLOSE,
662 SshMsgChannelClose.class);
663 messageStore.registerMessage(SshMsgChannelEOF.SSH_MSG_CHANNEL_EOF,
664 SshMsgChannelEOF.class);
665 messageStore.registerMessage(SshMsgChannelData.SSH_MSG_CHANNEL_DATA,
666 SshMsgChannelData.class);
667 messageStore.registerMessage(SshMsgChannelExtendedData.SSH_MSG_CHANNEL_EXTENDED_DATA,
668 SshMsgChannelExtendedData.class);
669 messageStore.registerMessage(SshMsgChannelFailure.SSH_MSG_CHANNEL_FAILURE,
670 SshMsgChannelFailure.class);
671 messageStore.registerMessage(SshMsgChannelRequest.SSH_MSG_CHANNEL_REQUEST,
672 SshMsgChannelRequest.class);
673 messageStore.registerMessage(SshMsgChannelSuccess.SSH_MSG_CHANNEL_SUCCESS,
674 SshMsgChannelSuccess.class);
675 messageStore.registerMessage(SshMsgChannelWindowAdjust.SSH_MSG_CHANNEL_WINDOW_ADJUST,
676 SshMsgChannelWindowAdjust.class);
677 messageStore.registerMessage(SshMsgGlobalRequest.SSH_MSG_GLOBAL_REQUEST,
678 SshMsgGlobalRequest.class);
679 messageStore.registerMessage(SshMsgRequestFailure.SSH_MSG_REQUEST_FAILURE,
680 SshMsgRequestFailure.class);
681 messageStore.registerMessage(SshMsgRequestSuccess.SSH_MSG_REQUEST_SUCCESS,
682 SshMsgRequestSuccess.class);
683 }
684
685 /**
686 *
687 */
688 protected void onServiceRequest() {
689 }
690
691 /**
692 *
693 *
694 * @param channel
695 *
696 * @throws IOException
697 */
698 protected void sendChannelFailure(Channel channel)
699 throws IOException {
700 SshMsgChannelFailure msg = new SshMsgChannelFailure(channel.getRemoteChannelId());
701 transport.sendMessage(msg, this);
702 }
703
704 /**
705 *
706 *
707 * @param channel
708 *
709 * @throws IOException
710 */
711 protected void sendChannelOpenConfirmation(Channel channel)
712 throws IOException {
713 SshMsgChannelOpenConfirmation msg = new SshMsgChannelOpenConfirmation(channel.getRemoteChannelId(),
714 channel.getLocalChannelId(),
715 channel.getLocalWindow().getWindowSpace(),
716 channel.getLocalPacketSize(),
717 channel.getChannelConfirmationData());
718 transport.sendMessage(msg, this);
719 }
720
721 /**
722 *
723 *
724 * @param remoteChannelId
725 * @param reasonCode
726 * @param additionalInfo
727 * @param languageTag
728 *
729 * @throws IOException
730 */
731 protected void sendChannelOpenFailure(long remoteChannelId,
732 long reasonCode, String additionalInfo, String languageTag)
733 throws IOException {
734 SshMsgChannelOpenFailure msg = new SshMsgChannelOpenFailure(remoteChannelId,
735 reasonCode, additionalInfo, languageTag);
736 transport.sendMessage(msg, this);
737 }
738
739 /**
740 *
741 *
742 * @throws IOException
743 */
744 protected void sendGlobalRequestFailure() throws IOException {
745 SshMsgRequestFailure msg = new SshMsgRequestFailure();
746 transport.sendMessage(msg, this);
747 }
748
749 /**
750 *
751 *
752 * @param requestData
753 *
754 * @throws IOException
755 */
756 protected void sendGlobalRequestSuccess(byte[] requestData)
757 throws IOException {
758 SshMsgRequestSuccess msg = new SshMsgRequestSuccess(requestData);
759 transport.sendMessage(msg, this);
760 }
761
762 private Channel getChannel(long channelId) throws IOException {
763 //synchronized (activeChannels) {
764 Long l = new Long(channelId);
765
766 if (!activeChannels.containsKey(l)) {
767 throw new IOException("Non existent channel " + l.toString() +
768 " requested");
769 }
770 return (Channel) activeChannels.get(l);
771 //}
772 }
773
774 private void onMsgChannelClose(SshMsgChannelClose msg)
775 throws IOException {
776 Channel channel = getChannel(msg.getRecipientChannel());
777
778 // If we have not already closed it then inform the subclasses
779 if (channel == null) {
780 throw new IOException("Remote computer tried to close a " +
781 "non existent channel " +
782 String.valueOf(msg.getRecipientChannel()));
783 }
784
785 log.info("Remote computer has closed channel " +
786 String.valueOf(channel.getLocalChannelId()) + "[" +
787 channel.getName() + "]");
788
789 // If the channel is not already closed then close it
790 if (channel.getState().getValue() != ChannelState.CHANNEL_CLOSED) {
791 channel.remoteClose();
792 }
793 }
794
795 private void onMsgChannelData(SshMsgChannelData msg)
796 throws IOException {
797 if (log.isDebugEnabled()) {
798 log.debug("Received " +
799 String.valueOf(msg.getChannelData().length) +
800 " bytes of data for channel id " +
801 String.valueOf(msg.getRecipientChannel()));
802 }
803
804 // Get the data's channel
805 Channel channel = getChannel(msg.getRecipientChannel());
806 channel.processChannelData(msg);
807 }
808
809 private void onMsgChannelEOF(SshMsgChannelEOF msg)
810 throws IOException {
811 Channel channel = getChannel(msg.getRecipientChannel());
812
813 try {
814 log.info("Remote computer has set channel " +
815 String.valueOf(msg.getRecipientChannel()) + " to EOF [" +
816 channel.getName() + "]");
817 channel.setRemoteEOF();
818 } catch (IOException ioe) {
819 log.info("Failed to close the ChannelInputStream after EOF event");
820 }
821 }
822
823 private void onMsgChannelExtendedData(SshMsgChannelExtendedData msg)
824 throws IOException {
825 Channel channel = getChannel(msg.getRecipientChannel());
826
827 if (channel == null) {
828 throw new IOException(
829 "Remote computer sent data for non existent channel");
830 }
831
832 channel.getLocalWindow().consumeWindowSpace(msg.getChannelData().length);
833 channel.processChannelData(msg);
834 }
835
836 private void onMsgChannelOpen(SshMsgChannelOpen msg)
837 throws IOException {
838 //synchronized (activeChannels) {
839 log.info("Request for " + msg.getChannelType() +
840 " channel recieved");
841
842 // Try to get the channel implementation from the allowed channels
843 ChannelFactory cf = (ChannelFactory) allowedChannels.get(msg.getChannelType());
844
845 if (cf == null) {
846 sendChannelOpenFailure(msg.getSenderChannelId(),
847 SshMsgChannelOpenFailure.SSH_OPEN_CONNECT_FAILED,
848 "The channel type is not supported", "");
849 log.info("Request for channel type " + msg.getChannelType() +
850 " refused");
851
852 return;
853 }
854
855 try {
856 log.info("Creating channel " + msg.getChannelType());
857
858 Channel channel = cf.createChannel(msg.getChannelType(),
859 msg.getChannelData());
860
861 // Initialize the channel
862 log.info("Initiating channel");
863
864 Long channelId = getChannelId();
865 channel.init(this, channelId.longValue(),
866 msg.getSenderChannelId(), msg.getInitialWindowSize(),
867 msg.getMaximumPacketSize());
868 activeChannels.put(channelId, channel);
869 log.info("Sending channel open confirmation");
870
871 // Send the confirmation message
872 sendChannelOpenConfirmation(channel);
873
874 // Open the channel for real
875 channel.open();
876 } catch (InvalidChannelException ice) {
877 sendChannelOpenFailure(msg.getSenderChannelId(),
878 SshMsgChannelOpenFailure.SSH_OPEN_CONNECT_FAILED,
879 ice.getMessage(), "");
880 }
881 //}
882 }
883
884 private void onMsgChannelRequest(SshMsgChannelRequest msg)
885 throws IOException {
886 Channel channel = getChannel(msg.getRecipientChannel());
887
888 if (channel == null) {
889 log.warn("Remote computer tried to make a request for " +
890 "a non existence channel!");
891 }
892
893 channel.onChannelRequest(msg.getRequestType(), msg.getWantReply(),
894 msg.getChannelData());
895 }
896
897 private void onMsgChannelWindowAdjust(SshMsgChannelWindowAdjust msg)
898 throws IOException {
899 Channel channel = getChannel(msg.getRecipientChannel());
900
901 if (channel == null) {
902 throw new IOException("Remote computer tried to increase " +
903 "window space for non existent channel " +
904 String.valueOf(msg.getRecipientChannel()));
905 }
906
907 channel.getRemoteWindow().increaseWindowSpace(msg.getBytesToAdd());
908
909 if (log.isDebugEnabled()) {
910 log.debug(String.valueOf(msg.getBytesToAdd()) +
911 " bytes added to remote window");
912 log.debug("Remote window space is " +
913 String.valueOf(channel.getRemoteWindow().getWindowSpace()));
914 }
915 }
916
917 private void onMsgGlobalRequest(SshMsgGlobalRequest msg)
918 throws IOException {
919 onGlobalRequest(msg.getRequestName(), msg.getWantReply(),
920 msg.getRequestData());
921 }
922
923 /**
924 *
925 *
926 * @param channel
927 */
928 protected void freeChannel(Channel channel) {
929 //synchronized (activeChannels) {
930 log.info("Freeing channel " +
931 String.valueOf(channel.getLocalChannelId()) + " [" +
932 channel.getName() + "]");
933
934 Long channelId = new Long(channel.getLocalChannelId());
935 activeChannels.remove(channelId);
936
937 //reusableChannels.add(channelId);
938 //}
939 }
940 }