KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > ch > ethz > ssh2 > channel > ChannelManager


1
2 package ch.ethz.ssh2.channel;
3
4 import java.io.IOException JavaDoc;
5 import java.util.HashMap JavaDoc;
6 import java.util.Vector JavaDoc;
7
8 import ch.ethz.ssh2.ChannelCondition;
9 import ch.ethz.ssh2.log.Logger;
10 import ch.ethz.ssh2.packets.PacketChannelOpenConfirmation;
11 import ch.ethz.ssh2.packets.PacketChannelOpenFailure;
12 import ch.ethz.ssh2.packets.PacketGlobalCancelForwardRequest;
13 import ch.ethz.ssh2.packets.PacketGlobalForwardRequest;
14 import ch.ethz.ssh2.packets.PacketOpenDirectTCPIPChannel;
15 import ch.ethz.ssh2.packets.PacketOpenSessionChannel;
16 import ch.ethz.ssh2.packets.PacketSessionExecCommand;
17 import ch.ethz.ssh2.packets.PacketSessionPtyRequest;
18 import ch.ethz.ssh2.packets.PacketSessionStartShell;
19 import ch.ethz.ssh2.packets.PacketSessionSubsystemRequest;
20 import ch.ethz.ssh2.packets.PacketSessionX11Request;
21 import ch.ethz.ssh2.packets.Packets;
22 import ch.ethz.ssh2.packets.TypesReader;
23 import ch.ethz.ssh2.transport.MessageHandler;
24 import ch.ethz.ssh2.transport.TransportManager;
25
26 /**
27  * ChannelManager. Please read the comments in Channel.java.
28  * <p>
29  * Besides the crypto part, this is the core of the library.
30  *
31  * @author Christian Plattner, plattner@inf.ethz.ch
32  * @version $Id: ChannelManager.java,v 1.15 2006/08/11 12:24:01 cplattne Exp $
33  */

34 public class ChannelManager implements MessageHandler
35 {
36     private static final Logger log = Logger.getLogger(ChannelManager.class);
37
38     private HashMap JavaDoc x11_magic_cookies = new HashMap JavaDoc();
39
40     private TransportManager tm;
41
42     private Vector JavaDoc channels = new Vector JavaDoc();
43     private int nextLocalChannel = 100;
44     private boolean shutdown = false;
45     private int globalSuccessCounter = 0;
46     private int globalFailedCounter = 0;
47
48     private HashMap JavaDoc remoteForwardings = new HashMap JavaDoc();
49
50     private Vector JavaDoc listenerThreads = new Vector JavaDoc();
51
52     private boolean listenerThreadsAllowed = true;
53
54     public ChannelManager(TransportManager tm)
55     {
56         this.tm = tm;
57         tm.registerMessageHandler(this, 80, 100);
58     }
59
60     private Channel getChannel(int id)
61     {
62         synchronized (channels)
63         {
64             for (int i = 0; i < channels.size(); i++)
65             {
66                 Channel c = (Channel) channels.elementAt(i);
67                 if (c.localID == id)
68                     return c;
69             }
70         }
71         return null;
72     }
73
74     private void removeChannel(int id)
75     {
76         synchronized (channels)
77         {
78             for (int i = 0; i < channels.size(); i++)
79             {
80                 Channel c = (Channel) channels.elementAt(i);
81                 if (c.localID == id)
82                 {
83                     channels.removeElementAt(i);
84                     break;
85                 }
86             }
87         }
88     }
89
90     private int addChannel(Channel c)
91     {
92         synchronized (channels)
93         {
94             channels.addElement(c);
95             return nextLocalChannel++;
96         }
97     }
98
99     private void waitUntilChannelOpen(Channel c) throws IOException JavaDoc
100     {
101         synchronized (c)
102         {
103             while (c.state == Channel.STATE_OPENING)
104             {
105                 try
106                 {
107                     c.wait();
108                 }
109                 catch (InterruptedException JavaDoc ignore)
110                 {
111                 }
112             }
113
114             if (c.state != Channel.STATE_OPEN)
115             {
116                 removeChannel(c.localID);
117
118                 String JavaDoc detail = c.getReasonClosed();
119
120                 if (detail == null)
121                     detail = "state: " + c.state;
122
123                 throw new IOException JavaDoc("Could not open channel (" + detail + ")");
124             }
125         }
126     }
127
128     private final void waitForGlobalSuccessOrFailure() throws IOException JavaDoc
129     {
130         synchronized (channels)
131         {
132             while ((globalSuccessCounter == 0) && (globalFailedCounter == 0))
133             {
134                 if (shutdown)
135                 {
136                     throw new IOException JavaDoc("The connection is being shutdown");
137                 }
138
139                 try
140                 {
141                     channels.wait();
142                 }
143                 catch (InterruptedException JavaDoc ignore)
144                 {
145                 }
146             }
147
148             if (globalFailedCounter != 0)
149             {
150                 throw new IOException JavaDoc("The server denied the request (did you enable port forwarding?)");
151             }
152
153             if (globalSuccessCounter == 0)
154             {
155                 throw new IOException JavaDoc("Illegal state.");
156             }
157
158         }
159     }
160
161     private final void waitForChannelSuccessOrFailure(Channel c) throws IOException JavaDoc
162     {
163         synchronized (c)
164         {
165             while ((c.successCounter == 0) && (c.failedCounter == 0))
166             {
167                 if (c.state != Channel.STATE_OPEN)
168                 {
169                     String JavaDoc detail = c.getReasonClosed();
170
171                     if (detail == null)
172                         detail = "state: " + c.state;
173
174                     throw new IOException JavaDoc("This SSH2 channel is not open (" + detail + ")");
175                 }
176
177                 try
178                 {
179                     c.wait();
180                 }
181                 catch (InterruptedException JavaDoc ignore)
182                 {
183                 }
184             }
185
186             if (c.failedCounter != 0)
187             {
188                 throw new IOException JavaDoc("The server denied the request.");
189             }
190         }
191     }
192
193     public void registerX11Cookie(String JavaDoc hexFakeCookie, X11ServerData data)
194     {
195         synchronized (x11_magic_cookies)
196         {
197             x11_magic_cookies.put(hexFakeCookie, data);
198         }
199     }
200
201     public void unRegisterX11Cookie(String JavaDoc hexFakeCookie, boolean killChannels)
202     {
203         if (hexFakeCookie == null)
204             throw new IllegalStateException JavaDoc("hexFakeCookie may not be null");
205
206         synchronized (x11_magic_cookies)
207         {
208             x11_magic_cookies.remove(hexFakeCookie);
209         }
210
211         if (killChannels == false)
212             return;
213
214         if (log.isEnabled())
215             log.log(50, "Closing all X11 channels for the given fake cookie");
216
217         Vector JavaDoc channel_copy;
218
219         synchronized (channels)
220         {
221             channel_copy = (Vector JavaDoc) channels.clone();
222         }
223
224         for (int i = 0; i < channel_copy.size(); i++)
225         {
226             Channel c = (Channel) channel_copy.elementAt(i);
227
228             synchronized (c)
229             {
230                 if (hexFakeCookie.equals(c.hexX11FakeCookie) == false)
231                     continue;
232             }
233
234             try
235             {
236                 closeChannel(c, "Closing X11 channel since the corresponding session is closing", true);
237             }
238             catch (IOException JavaDoc e)
239             {
240             }
241         }
242     }
243
244     public X11ServerData checkX11Cookie(String JavaDoc hexFakeCookie)
245     {
246         synchronized (x11_magic_cookies)
247         {
248             if (hexFakeCookie != null)
249                 return (X11ServerData) x11_magic_cookies.get(hexFakeCookie);
250         }
251         return null;
252     }
253
254     public void closeAllChannels()
255     {
256         if (log.isEnabled())
257             log.log(50, "Closing all channels");
258
259         Vector JavaDoc channel_copy;
260
261         synchronized (channels)
262         {
263             channel_copy = (Vector JavaDoc) channels.clone();
264         }
265
266         for (int i = 0; i < channel_copy.size(); i++)
267         {
268             Channel c = (Channel) channel_copy.elementAt(i);
269             try
270             {
271                 closeChannel(c, "Closing all channels", true);
272             }
273             catch (IOException JavaDoc e)
274             {
275             }
276         }
277     }
278
279     public void closeChannel(Channel c, String JavaDoc reason, boolean force) throws IOException JavaDoc
280     {
281         byte msg[] = new byte[5];
282
283         synchronized (c)
284         {
285             if (force)
286             {
287                 c.state = Channel.STATE_CLOSED;
288                 c.EOF = true;
289             }
290
291             c.setReasonClosed(reason);
292
293             msg[0] = Packets.SSH_MSG_CHANNEL_CLOSE;
294             msg[1] = (byte) (c.remoteID >> 24);
295             msg[2] = (byte) (c.remoteID >> 16);
296             msg[3] = (byte) (c.remoteID >> 8);
297             msg[4] = (byte) (c.remoteID);
298
299             c.notifyAll();
300         }
301
302         synchronized (c.channelSendLock)
303         {
304             if (c.closeMessageSent == true)
305                 return;
306             tm.sendMessage(msg);
307             c.closeMessageSent = true;
308         }
309
310         if (log.isEnabled())
311             log.log(50, "Sent SSH_MSG_CHANNEL_CLOSE (channel " + c.localID + ")");
312     }
313
314     public void sendEOF(Channel c) throws IOException JavaDoc
315     {
316         byte[] msg = new byte[5];
317
318         synchronized (c)
319         {
320             if (c.state != Channel.STATE_OPEN)
321                 return;
322
323             msg[0] = Packets.SSH_MSG_CHANNEL_EOF;
324             msg[1] = (byte) (c.remoteID >> 24);
325             msg[2] = (byte) (c.remoteID >> 16);
326             msg[3] = (byte) (c.remoteID >> 8);
327             msg[4] = (byte) (c.remoteID);
328         }
329
330         synchronized (c.channelSendLock)
331         {
332             if (c.closeMessageSent == true)
333                 return;
334             tm.sendMessage(msg);
335         }
336
337         if (log.isEnabled())
338             log.log(50, "Sent EOF (Channel " + c.localID + "/" + c.remoteID + ")");
339     }
340
341     public void sendOpenConfirmation(Channel c) throws IOException JavaDoc
342     {
343         PacketChannelOpenConfirmation pcoc = null;
344
345         synchronized (c)
346         {
347             if (c.state != Channel.STATE_OPENING)
348                 return;
349
350             c.state = Channel.STATE_OPEN;
351
352             pcoc = new PacketChannelOpenConfirmation(c.remoteID, c.localID, c.localWindow, c.localMaxPacketSize);
353         }
354
355         synchronized (c.channelSendLock)
356         {
357             if (c.closeMessageSent == true)
358                 return;
359             tm.sendMessage(pcoc.getPayload());
360         }
361     }
362
363     public void sendData(Channel c, byte[] buffer, int pos, int len) throws IOException JavaDoc
364     {
365         while (len > 0)
366         {
367             int thislen = 0;
368             byte[] msg;
369
370             synchronized (c)
371             {
372                 while (true)
373                 {
374                     if (c.state == Channel.STATE_CLOSED)
375                         throw new IOException JavaDoc("SSH channel is closed. (" + c.getReasonClosed() + ")");
376
377                     if (c.state != Channel.STATE_OPEN)
378                         throw new IOException JavaDoc("SSH channel in strange state. (" + c.state + ")");
379
380                     if (c.remoteWindow != 0)
381                         break;
382
383                     try
384                     {
385                         c.wait();
386                     }
387                     catch (InterruptedException JavaDoc ignore)
388                     {
389                     }
390                 }
391
392                 /* len > 0, no sign extension can happen when comparing */
393
394                 thislen = (c.remoteWindow >= len) ? len : (int) c.remoteWindow;
395
396                 int estimatedMaxDataLen = c.remoteMaxPacketSize - (tm.getPacketOverheadEstimate() + 9);
397
398                 /* The worst case scenario =) a true bottleneck */
399
400                 if (estimatedMaxDataLen <= 0)
401                 {
402                     estimatedMaxDataLen = 1;
403                 }
404
405                 if (thislen > estimatedMaxDataLen)
406                     thislen = estimatedMaxDataLen;
407
408                 c.remoteWindow -= thislen;
409
410                 msg = new byte[1 + 8 + thislen];
411
412                 msg[0] = Packets.SSH_MSG_CHANNEL_DATA;
413                 msg[1] = (byte) (c.remoteID >> 24);
414                 msg[2] = (byte) (c.remoteID >> 16);
415                 msg[3] = (byte) (c.remoteID >> 8);
416                 msg[4] = (byte) (c.remoteID);
417                 msg[5] = (byte) (thislen >> 24);
418                 msg[6] = (byte) (thislen >> 16);
419                 msg[7] = (byte) (thislen >> 8);
420                 msg[8] = (byte) (thislen);
421
422                 System.arraycopy(buffer, pos, msg, 9, thislen);
423             }
424
425             synchronized (c.channelSendLock)
426             {
427                 if (c.closeMessageSent == true)
428                     throw new IOException JavaDoc("SSH channel is closed. (" + c.getReasonClosed() + ")");
429
430                 tm.sendMessage(msg);
431             }
432
433             pos += thislen;
434             len -= thislen;
435         }
436     }
437
438     public int requestGlobalForward(String JavaDoc bindAddress, int bindPort, String JavaDoc targetAddress, int targetPort)
439             throws IOException JavaDoc
440     {
441         RemoteForwardingData rfd = new RemoteForwardingData();
442
443         rfd.bindAddress = bindAddress;
444         rfd.bindPort = bindPort;
445         rfd.targetAddress = targetAddress;
446         rfd.targetPort = targetPort;
447
448         synchronized (remoteForwardings)
449         {
450             Integer JavaDoc key = new Integer JavaDoc(bindPort);
451
452             if (remoteForwardings.get(key) != null)
453             {
454                 throw new IOException JavaDoc("There is already a forwarding for remote port " + bindPort);
455             }
456
457             remoteForwardings.put(key, rfd);
458         }
459
460         synchronized (channels)
461         {
462             globalSuccessCounter = globalFailedCounter = 0;
463         }
464
465         PacketGlobalForwardRequest pgf = new PacketGlobalForwardRequest(true, bindAddress, bindPort);
466         tm.sendMessage(pgf.getPayload());
467
468         if (log.isEnabled())
469             log.log(50, "Requesting a remote forwarding ('" + bindAddress + "', " + bindPort + ")");
470
471         try
472         {
473             waitForGlobalSuccessOrFailure();
474         }
475         catch (IOException JavaDoc e)
476         {
477             synchronized (remoteForwardings)
478             {
479                 remoteForwardings.remove(rfd);
480             }
481             throw e;
482         }
483
484         return bindPort;
485     }
486
487     public void requestCancelGlobalForward(int bindPort) throws IOException JavaDoc
488     {
489         RemoteForwardingData rfd = null;
490
491         synchronized (remoteForwardings)
492         {
493             rfd = (RemoteForwardingData) remoteForwardings.get(new Integer JavaDoc(bindPort));
494
495             if (rfd == null)
496                 throw new IOException JavaDoc("Sorry, there is no known remote forwarding for remote port " + bindPort);
497         }
498
499         synchronized (channels)
500         {
501             globalSuccessCounter = globalFailedCounter = 0;
502         }
503
504         PacketGlobalCancelForwardRequest pgcf = new PacketGlobalCancelForwardRequest(true, rfd.bindAddress,
505                 rfd.bindPort);
506         tm.sendMessage(pgcf.getPayload());
507
508         if (log.isEnabled())
509             log.log(50, "Requesting cancelation of remote forward ('" + rfd.bindAddress + "', " + rfd.bindPort + ")");
510
511         waitForGlobalSuccessOrFailure();
512
513         /* Only now we are sure that no more forwarded connections will arrive */
514
515         synchronized (remoteForwardings)
516         {
517             remoteForwardings.remove(rfd);
518         }
519     }
520
521     public void registerThread(IChannelWorkerThread thr) throws IOException JavaDoc
522     {
523         synchronized (listenerThreads)
524         {
525             if (listenerThreadsAllowed == false)
526                 throw new IOException JavaDoc("Too late, this connection is closed.");
527             listenerThreads.addElement(thr);
528         }
529     }
530
531     public Channel openDirectTCPIPChannel(String JavaDoc host_to_connect, int port_to_connect, String JavaDoc originator_IP_address,
532             int originator_port) throws IOException JavaDoc
533     {
534         Channel c = new Channel(this);
535
536         synchronized (c)
537         {
538             c.localID = addChannel(c);
539             // end of synchronized block forces writing out to main memory
540
}
541
542         PacketOpenDirectTCPIPChannel dtc = new PacketOpenDirectTCPIPChannel(c.localID, c.localWindow,
543                 c.localMaxPacketSize, host_to_connect, port_to_connect, originator_IP_address, originator_port);
544
545         tm.sendMessage(dtc.getPayload());
546
547         waitUntilChannelOpen(c);
548
549         return c;
550     }
551
552     public Channel openSessionChannel() throws IOException JavaDoc
553     {
554         Channel c = new Channel(this);
555
556         synchronized (c)
557         {
558             c.localID = addChannel(c);
559             // end of synchronized block forces the writing out to main memory
560
}
561
562         if (log.isEnabled())
563             log.log(50, "Sending SSH_MSG_CHANNEL_OPEN (Channel " + c.localID + ")");
564
565         PacketOpenSessionChannel smo = new PacketOpenSessionChannel(c.localID, c.localWindow, c.localMaxPacketSize);
566         tm.sendMessage(smo.getPayload());
567
568         waitUntilChannelOpen(c);
569
570         return c;
571     }
572
573     public void requestPTY(Channel c, String JavaDoc term, int term_width_characters, int term_height_characters,
574             int term_width_pixels, int term_height_pixels, byte[] terminal_modes) throws IOException JavaDoc
575     {
576         PacketSessionPtyRequest spr;
577
578         synchronized (c)
579         {
580             if (c.state != Channel.STATE_OPEN)
581                 throw new IOException JavaDoc("Cannot request PTY on this channel (" + c.getReasonClosed() + ")");
582
583             spr = new PacketSessionPtyRequest(c.remoteID, true, term, term_width_characters, term_height_characters,
584                     term_width_pixels, term_height_pixels, terminal_modes);
585
586             c.successCounter = c.failedCounter = 0;
587         }
588
589         synchronized (c.channelSendLock)
590         {
591             if (c.closeMessageSent)
592                 throw new IOException JavaDoc("Cannot request PTY on this channel (" + c.getReasonClosed() + ")");
593             tm.sendMessage(spr.getPayload());
594         }
595
596         try
597         {
598             waitForChannelSuccessOrFailure(c);
599         }
600         catch (IOException JavaDoc e)
601         {
602             throw (IOException JavaDoc) new IOException JavaDoc("PTY request failed").initCause(e);
603         }
604     }
605
606     public void requestX11(Channel c, boolean singleConnection, String JavaDoc x11AuthenticationProtocol,
607             String JavaDoc x11AuthenticationCookie, int x11ScreenNumber) throws IOException JavaDoc
608     {
609         PacketSessionX11Request psr;
610
611         synchronized (c)
612         {
613             if (c.state != Channel.STATE_OPEN)
614                 throw new IOException JavaDoc("Cannot request X11 on this channel (" + c.getReasonClosed() + ")");
615
616             psr = new PacketSessionX11Request(c.remoteID, true, singleConnection, x11AuthenticationProtocol,
617                     x11AuthenticationCookie, x11ScreenNumber);
618
619             c.successCounter = c.failedCounter = 0;
620         }
621
622         synchronized (c.channelSendLock)
623         {
624             if (c.closeMessageSent)
625                 throw new IOException JavaDoc("Cannot request X11 on this channel (" + c.getReasonClosed() + ")");
626             tm.sendMessage(psr.getPayload());
627         }
628
629         if (log.isEnabled())
630             log.log(50, "Requesting X11 forwarding (Channel " + c.localID + "/" + c.remoteID + ")");
631
632         try
633         {
634             waitForChannelSuccessOrFailure(c);
635         }
636         catch (IOException JavaDoc e)
637         {
638             throw (IOException JavaDoc) new IOException JavaDoc("The X11 request failed.").initCause(e);
639         }
640     }
641
642     public void requestSubSystem(Channel c, String JavaDoc subSystemName) throws IOException JavaDoc
643     {
644         PacketSessionSubsystemRequest ssr;
645
646         synchronized (c)
647         {
648             if (c.state != Channel.STATE_OPEN)
649                 throw new IOException JavaDoc("Cannot request subsystem on this channel (" + c.getReasonClosed() + ")");
650
651             ssr = new PacketSessionSubsystemRequest(c.remoteID, true, subSystemName);
652
653             c.successCounter = c.failedCounter = 0;
654         }
655
656         synchronized (c.channelSendLock)
657         {
658             if (c.closeMessageSent)
659                 throw new IOException JavaDoc("Cannot request subsystem on this channel (" + c.getReasonClosed() + ")");
660             tm.sendMessage(ssr.getPayload());
661         }
662
663         try
664         {
665             waitForChannelSuccessOrFailure(c);
666         }
667         catch (IOException JavaDoc e)
668         {
669             throw (IOException JavaDoc) new IOException JavaDoc("The subsystem request failed.").initCause(e);
670         }
671     }
672
673     public void requestExecCommand(Channel c, String JavaDoc cmd) throws IOException JavaDoc
674     {
675         PacketSessionExecCommand sm;
676
677         synchronized (c)
678         {
679             if (c.state != Channel.STATE_OPEN)
680                 throw new IOException JavaDoc("Cannot execute command on this channel (" + c.getReasonClosed() + ")");
681
682             sm = new PacketSessionExecCommand(c.remoteID, true, cmd);
683
684             c.successCounter = c.failedCounter = 0;
685         }
686
687         synchronized (c.channelSendLock)
688         {
689             if (c.closeMessageSent)
690                 throw new IOException JavaDoc("Cannot execute command on this channel (" + c.getReasonClosed() + ")");
691             tm.sendMessage(sm.getPayload());
692         }
693
694         if (log.isEnabled())
695             log.log(50, "Executing command (channel " + c.localID + ", '" + cmd + "')");
696
697         try
698         {
699             waitForChannelSuccessOrFailure(c);
700         }
701         catch (IOException JavaDoc e)
702         {
703             throw (IOException JavaDoc) new IOException JavaDoc("The execute request failed.").initCause(e);
704         }
705     }
706
707     public void requestShell(Channel c) throws IOException JavaDoc
708     {
709         PacketSessionStartShell sm;
710
711         synchronized (c)
712         {
713             if (c.state != Channel.STATE_OPEN)
714                 throw new IOException JavaDoc("Cannot start shell on this channel (" + c.getReasonClosed() + ")");
715
716             sm = new PacketSessionStartShell(c.remoteID, true);
717
718             c.successCounter = c.failedCounter = 0;
719         }
720
721         synchronized (c.channelSendLock)
722         {
723             if (c.closeMessageSent)
724                 throw new IOException JavaDoc("Cannot start shell on this channel (" + c.getReasonClosed() + ")");
725             tm.sendMessage(sm.getPayload());
726         }
727
728         try
729         {
730             waitForChannelSuccessOrFailure(c);
731         }
732         catch (IOException JavaDoc e)
733         {
734             throw (IOException JavaDoc) new IOException JavaDoc("The shell request failed.").initCause(e);
735         }
736     }
737
738     public void msgChannelExtendedData(byte[] msg, int msglen) throws IOException JavaDoc
739     {
740         if (msglen <= 13)
741             throw new IOException JavaDoc("SSH_MSG_CHANNEL_EXTENDED_DATA message has wrong size (" + msglen + ")");
742
743         int id = ((msg[1] & 0xff) << 24) | ((msg[2] & 0xff) << 16) | ((msg[3] & 0xff) << 8) | (msg[4] & 0xff);
744         int dataType = ((msg[5] & 0xff) << 24) | ((msg[6] & 0xff) << 16) | ((msg[7] & 0xff) << 8) | (msg[8] & 0xff);
745         int len = ((msg[9] & 0xff) << 24) | ((msg[10] & 0xff) << 16) | ((msg[11] & 0xff) << 8) | (msg[12] & 0xff);
746
747         Channel c = getChannel(id);
748
749         if (c == null)
750             throw new IOException JavaDoc("Unexpected SSH_MSG_CHANNEL_EXTENDED_DATA message for non-existent channel " + id);
751
752         if (dataType != Packets.SSH_EXTENDED_DATA_STDERR)
753             throw new IOException JavaDoc("SSH_MSG_CHANNEL_EXTENDED_DATA message has unknown type (" + dataType + ")");
754
755         if (len != (msglen - 13))
756             throw new IOException JavaDoc("SSH_MSG_CHANNEL_EXTENDED_DATA message has wrong len (calculated " + (msglen - 13)
757                     + ", got " + len + ")");
758
759         if (log.isEnabled())
760             log.log(80, "Got SSH_MSG_CHANNEL_EXTENDED_DATA (channel " + id + ", " + len + ")");
761
762         synchronized (c)
763         {
764             if (c.state == Channel.STATE_CLOSED)
765                 return; // ignore
766

767             if (c.state != Channel.STATE_OPEN)
768                 throw new IOException JavaDoc("Got SSH_MSG_CHANNEL_EXTENDED_DATA, but channel is not in correct state ("
769                         + c.state + ")");
770
771             if (c.localWindow < len)
772                 throw new IOException JavaDoc("Remote sent too much data, does not fit into window.");
773
774             c.localWindow -= len;
775
776             System.arraycopy(msg, 13, c.stderrBuffer, c.stderrWritepos, len);
777             c.stderrWritepos += len;
778
779             c.notifyAll();
780         }
781     }
782
783     /**
784      * Wait until for a condition.
785      *
786      * @param c
787      * Channel
788      * @param timeout
789      * in ms, 0 means no timeout.
790      * @param condition_mask
791      * minimum event mask
792      * @return all current events
793      *
794      */

795     public int waitForCondition(Channel c, long timeout, int condition_mask)
796     {
797         long end_time = 0;
798         boolean end_time_set = false;
799
800         synchronized (c)
801         {
802             while (true)
803             {
804                 int current_cond = 0;
805
806                 int stdoutAvail = c.stdoutWritepos - c.stdoutReadpos;
807                 int stderrAvail = c.stderrWritepos - c.stderrReadpos;
808
809                 if (stdoutAvail > 0)
810                     current_cond = current_cond | ChannelCondition.STDOUT_DATA;
811
812                 if (stderrAvail > 0)
813                     current_cond = current_cond | ChannelCondition.STDERR_DATA;
814
815                 if (c.EOF)
816                     current_cond = current_cond | ChannelCondition.EOF;
817
818                 if (c.getExitStatus() != null)
819                     current_cond = current_cond | ChannelCondition.EXIT_STATUS;
820
821                 if (c.getExitSignal() != null)
822                     current_cond = current_cond | ChannelCondition.EXIT_SIGNAL;
823
824                 if (c.state == Channel.STATE_CLOSED)
825                     return current_cond | ChannelCondition.CLOSED | ChannelCondition.EOF;
826
827                 if ((current_cond & condition_mask) != 0)
828                     return current_cond;
829
830                 if (timeout > 0)
831                 {
832                     if (!end_time_set)
833                     {
834                         end_time = System.currentTimeMillis() + timeout;
835                         end_time_set = true;
836                     }
837                     else
838                     {
839                         timeout = end_time - System.currentTimeMillis();
840
841                         if (timeout <= 0)
842                             return current_cond | ChannelCondition.TIMEOUT;
843                     }
844                 }
845
846                 try
847                 {
848                     if (timeout > 0)
849                         c.wait(timeout);
850                     else
851                         c.wait();
852                 }
853                 catch (InterruptedException JavaDoc e)
854                 {
855                 }
856             }
857         }
858     }
859
860     public int getAvailable(Channel c, boolean extended) throws IOException JavaDoc
861     {
862         synchronized (c)
863         {
864             int avail;
865
866             if (extended)
867                 avail = c.stderrWritepos - c.stderrReadpos;
868             else
869                 avail = c.stdoutWritepos - c.stdoutReadpos;
870
871             return ((avail > 0) ? avail : (c.EOF ? -1 : 0));
872         }
873     }
874
875     public int getChannelData(Channel c, boolean extended, byte[] target, int off, int len) throws IOException JavaDoc
876     {
877         int copylen = 0;
878         int increment = 0;
879         int remoteID = 0;
880         int localID = 0;
881
882         synchronized (c)
883         {
884             int stdoutAvail = 0;
885             int stderrAvail = 0;
886
887             while (true)
888             {
889                 /*
890                  * Data available? We have to return remaining data even if the
891                  * channel is already closed.
892                  */

893
894                 stdoutAvail = c.stdoutWritepos - c.stdoutReadpos;
895                 stderrAvail = c.stderrWritepos - c.stderrReadpos;
896
897                 if ((!extended) && (stdoutAvail != 0))
898                     break;
899
900                 if ((extended) && (stderrAvail != 0))
901                     break;
902
903                 /* Do not wait if more data will never arrive (EOF or CLOSED) */
904
905                 if ((c.EOF) || (c.state != Channel.STATE_OPEN))
906                     return -1;
907
908                 try
909                 {
910                     c.wait();
911                 }
912                 catch (InterruptedException JavaDoc ignore)
913                 {
914                 }
915             }
916
917             /* OK, there is some data. Return it. */
918
919             if (!extended)
920             {
921                 copylen = (stdoutAvail > len) ? len : stdoutAvail;
922                 System.arraycopy(c.stdoutBuffer, c.stdoutReadpos, target, off, copylen);
923                 c.stdoutReadpos += copylen;
924
925                 if (c.stdoutReadpos != c.stdoutWritepos)
926
927                     System.arraycopy(c.stdoutBuffer, c.stdoutReadpos, c.stdoutBuffer, 0, c.stdoutWritepos
928                             - c.stdoutReadpos);
929
930                 c.stdoutWritepos -= c.stdoutReadpos;
931                 c.stdoutReadpos = 0;
932             }
933             else
934             {
935                 copylen = (stderrAvail > len) ? len : stderrAvail;
936                 System.arraycopy(c.stderrBuffer, c.stderrReadpos, target, off, copylen);
937                 c.stderrReadpos += copylen;
938
939                 if (c.stderrReadpos != c.stderrWritepos)
940
941                     System.arraycopy(c.stderrBuffer, c.stderrReadpos, c.stderrBuffer, 0, c.stderrWritepos
942                             - c.stderrReadpos);
943
944                 c.stderrWritepos -= c.stderrReadpos;
945                 c.stderrReadpos = 0;
946             }
947
948             if (c.state != Channel.STATE_OPEN)
949                 return copylen;
950
951             if (c.localWindow < ((Channel.CHANNEL_BUFFER_SIZE + 1) / 2))
952             {
953                 int minFreeSpace = Math.min(Channel.CHANNEL_BUFFER_SIZE - c.stdoutWritepos, Channel.CHANNEL_BUFFER_SIZE
954                         - c.stderrWritepos);
955
956                 increment = minFreeSpace - c.localWindow;
957                 c.localWindow = minFreeSpace;
958             }
959
960             remoteID = c.remoteID; /* read while holding the lock */
961             localID = c.localID; /* read while holding the lock */
962         }
963
964         /*
965          * If a consumer reads stdout and stdin in parallel, we may end up with
966          * sending two msgWindowAdjust messages. Luckily, it
967          * does not matter in which order they arrive at the server.
968          */

969
970         if (increment > 0)
971         {
972             if (log.isEnabled())
973                 log.log(80, "Sending SSH_MSG_CHANNEL_WINDOW_ADJUST (channel " + localID + ", " + increment + ")");
974
975             synchronized (c.channelSendLock)
976             {
977                 byte[] msg = c.msgWindowAdjust;
978
979                 msg[0] = Packets.SSH_MSG_CHANNEL_WINDOW_ADJUST;
980                 msg[1] = (byte) (remoteID >> 24);
981                 msg[2] = (byte) (remoteID >> 16);
982                 msg[3] = (byte) (remoteID >> 8);
983                 msg[4] = (byte) (remoteID);
984                 msg[5] = (byte) (increment >> 24);
985                 msg[6] = (byte) (increment >> 16);
986                 msg[7] = (byte) (increment >> 8);
987                 msg[8] = (byte) (increment);
988
989                 if (c.closeMessageSent == false)
990                     tm.sendMessage(msg);
991             }
992         }
993
994         return copylen;
995     }
996
997     public void msgChannelData(byte[] msg, int msglen) throws IOException JavaDoc
998     {
999         if (msglen <= 9)
1000            throw new IOException JavaDoc("SSH_MSG_CHANNEL_DATA message has wrong size (" + msglen + ")");
1001
1002        int id = ((msg[1] & 0xff) << 24) | ((msg[2] & 0xff) << 16) | ((msg[3] & 0xff) << 8) | (msg[4] & 0xff);
1003        int len = ((msg[5] & 0xff) << 24) | ((msg[6] & 0xff) << 16) | ((msg[7] & 0xff) << 8) | (msg[8] & 0xff);
1004
1005        Channel c = getChannel(id);
1006
1007        if (c == null)
1008            throw new IOException JavaDoc("Unexpected SSH_MSG_CHANNEL_DATA message for non-existent channel " + id);
1009
1010        if (len != (msglen - 9))
1011            throw new IOException JavaDoc("SSH_MSG_CHANNEL_DATA message has wrong len (calculated " + (msglen - 9) + ", got "
1012                    + len + ")");
1013
1014        if (log.isEnabled())
1015            log.log(80, "Got SSH_MSG_CHANNEL_DATA (channel " + id + ", " + len + ")");
1016
1017        synchronized (c)
1018        {
1019            if (c.state == Channel.STATE_CLOSED)
1020                return; // ignore
1021

1022            if (c.state != Channel.STATE_OPEN)
1023                throw new IOException JavaDoc("Got SSH_MSG_CHANNEL_DATA, but channel is not in correct state (" + c.state + ")");
1024
1025            if (c.localWindow < len)
1026                throw new IOException JavaDoc("Remote sent too much data, does not fit into window.");
1027
1028            c.localWindow -= len;
1029
1030            System.arraycopy(msg, 9, c.stdoutBuffer, c.stdoutWritepos, len);
1031            c.stdoutWritepos += len;
1032
1033            c.notifyAll();
1034        }
1035    }
1036
1037    public void msgChannelWindowAdjust(byte[] msg, int msglen) throws IOException JavaDoc
1038    {
1039        if (msglen != 9)
1040            throw new IOException JavaDoc("SSH_MSG_CHANNEL_WINDOW_ADJUST message has wrong size (" + msglen + ")");
1041
1042        int id = ((msg[1] & 0xff) << 24) | ((msg[2] & 0xff) << 16) | ((msg[3] & 0xff) << 8) | (msg[4] & 0xff);
1043        int windowChange = ((msg[5] & 0xff) << 24) | ((msg[6] & 0xff) << 16) | ((msg[7] & 0xff) << 8) | (msg[8] & 0xff);
1044
1045        Channel c = getChannel(id);
1046
1047        if (c == null)
1048            throw new IOException JavaDoc("Unexpected SSH_MSG_CHANNEL_WINDOW_ADJUST message for non-existent channel " + id);
1049
1050        synchronized (c)
1051        {
1052            final long huge = 0xFFFFffffL; /* 2^32 - 1 */
1053
1054            c.remoteWindow += (windowChange & huge); /* avoid sign extension */
1055
1056            /* TODO - is this a good heuristic? */
1057
1058            if ((c.remoteWindow > huge))
1059                c.remoteWindow = huge;
1060
1061            c.notifyAll();
1062        }
1063
1064        if (log.isEnabled())
1065            log.log(80, "Got SSH_MSG_CHANNEL_WINDOW_ADJUST (channel " + id + ", " + windowChange + ")");
1066    }
1067
1068    public void msgChannelOpen(byte[] msg, int msglen) throws IOException JavaDoc
1069    {
1070        TypesReader tr = new TypesReader(msg, 0, msglen);
1071
1072        tr.readByte(); // skip packet type
1073
String JavaDoc channelType = tr.readString();
1074        int remoteID = tr.readUINT32(); /* sender channel */
1075        int remoteWindow = tr.readUINT32(); /* initial window size */
1076        int remoteMaxPacketSize = tr.readUINT32(); /* maximum packet size */
1077
1078        if ("x11".equals(channelType))
1079        {
1080            synchronized (x11_magic_cookies)
1081            {
1082                /* If we did not request X11 forwarding, then simply ignore this bogus request. */
1083
1084                if (x11_magic_cookies.size() == 0)
1085                {
1086                    PacketChannelOpenFailure pcof = new PacketChannelOpenFailure(remoteID,
1087                            Packets.SSH_OPEN_ADMINISTRATIVELY_PROHIBITED, "X11 forwarding not activated", "");
1088
1089                    tm.sendAsynchronousMessage(pcof.getPayload());
1090
1091                    if (log.isEnabled())
1092                        log.log(20, "Unexpected X11 request, denying it!");
1093
1094                    return;
1095                }
1096            }
1097
1098            String JavaDoc remoteOriginatorAddress = tr.readString();
1099            int remoteOriginatorPort = tr.readUINT32();
1100
1101            Channel c = new Channel(this);
1102
1103            synchronized (c)
1104            {
1105                c.remoteID = remoteID;
1106                c.remoteWindow = remoteWindow & 0xFFFFffffL; /* properly convert UINT32 to long */
1107                c.remoteMaxPacketSize = remoteMaxPacketSize;
1108                c.localID = addChannel(c);
1109            }
1110
1111            /*
1112             * The open confirmation message will be sent from another thread
1113             */

1114
1115            RemoteX11AcceptThread rxat = new RemoteX11AcceptThread(c, remoteOriginatorAddress, remoteOriginatorPort);
1116            rxat.setDaemon(true);
1117            rxat.start();
1118
1119            return;
1120        }
1121
1122        if ("forwarded-tcpip".equals(channelType))
1123        {
1124            String JavaDoc remoteConnectedAddress = tr.readString(); /* address that was connected */
1125            int remoteConnectedPort = tr.readUINT32(); /* port that was connected */
1126            String JavaDoc remoteOriginatorAddress = tr.readString(); /* originator IP address */
1127            int remoteOriginatorPort = tr.readUINT32(); /* originator port */
1128
1129            RemoteForwardingData rfd = null;
1130
1131            synchronized (remoteForwardings)
1132            {
1133                rfd = (RemoteForwardingData) remoteForwardings.get(new Integer JavaDoc(remoteConnectedPort));
1134            }
1135
1136            if (rfd == null)
1137            {
1138                PacketChannelOpenFailure pcof = new PacketChannelOpenFailure(remoteID,
1139                        Packets.SSH_OPEN_ADMINISTRATIVELY_PROHIBITED,
1140                        "No thanks, unknown port in forwarded-tcpip request", "");
1141
1142                /* Always try to be polite. */
1143
1144                tm.sendAsynchronousMessage(pcof.getPayload());
1145
1146                if (log.isEnabled())
1147                    log.log(20, "Unexpected forwarded-tcpip request, denying it!");
1148
1149                return;
1150            }
1151
1152            Channel c = new Channel(this);
1153
1154            synchronized (c)
1155            {
1156                c.remoteID = remoteID;
1157                c.remoteWindow = remoteWindow & 0xFFFFffffL; /* convert UINT32 to long */
1158                c.remoteMaxPacketSize = remoteMaxPacketSize;
1159                c.localID = addChannel(c);
1160            }
1161
1162            /*
1163             * The open confirmation message will be sent from another thread.
1164             */

1165
1166            RemoteAcceptThread rat = new RemoteAcceptThread(c, remoteConnectedAddress, remoteConnectedPort,
1167                    remoteOriginatorAddress, remoteOriginatorPort, rfd.targetAddress, rfd.targetPort);
1168
1169            rat.setDaemon(true);
1170            rat.start();
1171
1172            return;
1173        }
1174
1175        /* Tell the server that we have no idea what it is talking about */
1176
1177        PacketChannelOpenFailure pcof = new PacketChannelOpenFailure(remoteID, Packets.SSH_OPEN_UNKNOWN_CHANNEL_TYPE,
1178                "Unknown channel type", "");
1179
1180        tm.sendAsynchronousMessage(pcof.getPayload());
1181
1182        if (log.isEnabled())
1183            log.log(20, "The peer tried to open an unsupported channel type (" + channelType + ")");
1184    }
1185
1186    public void msgChannelRequest(byte[] msg, int msglen) throws IOException JavaDoc
1187    {
1188        TypesReader tr = new TypesReader(msg, 0, msglen);
1189
1190        tr.readByte(); // skip packet type
1191
int id = tr.readUINT32();
1192
1193        Channel c = getChannel(id);
1194
1195        if (c == null)
1196            throw new IOException JavaDoc("Unexpected SSH_MSG_CHANNEL_REQUEST message for non-existent channel " + id);
1197
1198        String JavaDoc type = tr.readString("US-ASCII");
1199        boolean wantReply = tr.readBoolean();
1200
1201        if (log.isEnabled())
1202            log.log(80, "Got SSH_MSG_CHANNEL_REQUEST (channel " + id + ", '" + type + "')");
1203
1204        if (type.equals("exit-status"))
1205        {
1206            if (wantReply != false)
1207                throw new IOException JavaDoc("Badly formatted SSH_MSG_CHANNEL_REQUEST message, 'want reply' is true");
1208
1209            int exit_status = tr.readUINT32();
1210
1211            if (tr.remain() != 0)
1212                throw new IOException JavaDoc("Badly formatted SSH_MSG_CHANNEL_REQUEST message");
1213
1214            synchronized (c)
1215            {
1216                c.exit_status = new Integer JavaDoc(exit_status);
1217                c.notifyAll();
1218            }
1219
1220            if (log.isEnabled())
1221                log.log(50, "Got EXIT STATUS (channel " + id + ", status " + exit_status + ")");
1222
1223            return;
1224        }
1225
1226        if (type.equals("exit-signal"))
1227        {
1228            if (wantReply != false)
1229                throw new IOException JavaDoc("Badly formatted SSH_MSG_CHANNEL_REQUEST message, 'want reply' is true");
1230
1231            String JavaDoc signame = tr.readString("US-ASCII");
1232            tr.readBoolean();
1233            tr.readString();
1234            tr.readString();
1235
1236            if (tr.remain() != 0)
1237                throw new IOException JavaDoc("Badly formatted SSH_MSG_CHANNEL_REQUEST message");
1238
1239            synchronized (c)
1240            {
1241                c.exit_signal = signame;
1242                c.notifyAll();
1243            }
1244
1245            if (log.isEnabled())
1246                log.log(50, "Got EXIT SIGNAL (channel " + id + ", signal " + signame + ")");
1247
1248            return;
1249        }
1250
1251        /* We simply ignore unknown channel requests, however, if the server wants a reply,
1252         * then we signal that we have no idea what it is about.
1253         */

1254
1255        if (wantReply)
1256        {
1257            byte[] reply = new byte[5];
1258
1259            reply[0] = Packets.SSH_MSG_CHANNEL_FAILURE;
1260            reply[1] = (byte) (c.remoteID >> 24);
1261            reply[2] = (byte) (c.remoteID >> 16);
1262            reply[3] = (byte) (c.remoteID >> 8);
1263            reply[4] = (byte) (c.remoteID);
1264
1265            tm.sendAsynchronousMessage(reply);
1266        }
1267
1268        if (log.isEnabled())
1269            log.log(50, "Channel request '" + type + "' is not known, ignoring it");
1270    }
1271
1272    public void msgChannelEOF(byte[] msg, int msglen) throws IOException JavaDoc
1273    {
1274        if (msglen != 5)
1275            throw new IOException JavaDoc("SSH_MSG_CHANNEL_EOF message has wrong size (" + msglen + ")");
1276
1277        int id = ((msg[1] & 0xff) << 24) | ((msg[2] & 0xff) << 16) | ((msg[3] & 0xff) << 8) | (msg[4] & 0xff);
1278
1279        Channel c = getChannel(id);
1280
1281        if (c == null)
1282            throw new IOException JavaDoc("Unexpected SSH_MSG_CHANNEL_EOF message for non-existent channel " + id);
1283
1284        synchronized (c)
1285        {
1286            c.EOF = true;
1287            c.notifyAll();
1288        }
1289
1290        if (log.isEnabled())
1291            log.log(50, "Got SSH_MSG_CHANNEL_EOF (channel " + id + ")");
1292    }
1293
1294    public void msgChannelClose(byte[] msg, int msglen) throws IOException JavaDoc
1295    {
1296        if (msglen != 5)
1297            throw new IOException JavaDoc("SSH_MSG_CHANNEL_CLOSE message has wrong size (" + msglen + ")");
1298
1299        int id = ((msg[1] & 0xff) << 24) | ((msg[2] & 0xff) << 16) | ((msg[3] & 0xff) << 8) | (msg[4] & 0xff);
1300
1301        Channel c = getChannel(id);
1302
1303        if (c == null)
1304            throw new IOException JavaDoc("Unexpected SSH_MSG_CHANNEL_CLOSE message for non-existent channel " + id);
1305
1306        synchronized (c)
1307        {
1308            c.EOF = true;
1309            c.state = Channel.STATE_CLOSED;
1310            c.setReasonClosed("Close requested by remote");
1311            c.closeMessageRecv = true;
1312
1313            removeChannel(c.localID);
1314
1315            c.notifyAll();
1316        }
1317
1318        if (log.isEnabled())
1319            log.log(50, "Got SSH_MSG_CHANNEL_CLOSE (channel " + id + ")");
1320    }
1321
1322    public void msgChannelSuccess(byte[] msg, int msglen) throws IOException JavaDoc
1323    {
1324        if (msglen != 5)
1325            throw new IOException JavaDoc("SSH_MSG_CHANNEL_SUCCESS message has wrong size (" + msglen + ")");
1326
1327        int id = ((msg[1] & 0xff) << 24) | ((msg[2] & 0xff) << 16) | ((msg[3] & 0xff) << 8) | (msg[4] & 0xff);
1328
1329        Channel c = getChannel(id);
1330
1331        if (c == null)
1332            throw new IOException JavaDoc("Unexpected SSH_MSG_CHANNEL_SUCCESS message for non-existent channel " + id);
1333
1334        synchronized (c)
1335        {
1336            c.successCounter++;
1337            c.notifyAll();
1338        }
1339
1340        if (log.isEnabled())
1341            log.log(80, "Got SSH_MSG_CHANNEL_SUCCESS (channel " + id + ")");
1342    }
1343
1344    public void msgChannelFailure(byte[] msg, int msglen) throws IOException JavaDoc
1345    {
1346        if (msglen != 5)
1347            throw new IOException JavaDoc("SSH_MSG_CHANNEL_FAILURE message has wrong size (" + msglen + ")");
1348
1349        int id = ((msg[1] & 0xff) << 24) | ((msg[2] & 0xff) << 16) | ((msg[3] & 0xff) << 8) | (msg[4] & 0xff);
1350
1351        Channel c = getChannel(id);
1352
1353        if (c == null)
1354            throw new IOException JavaDoc("Unexpected SSH_MSG_CHANNEL_FAILURE message for non-existent channel " + id);
1355
1356        synchronized (c)
1357        {
1358            c.failedCounter++;
1359            c.notifyAll();
1360        }
1361
1362        if (log.isEnabled())
1363            log.log(50, "Got SSH_MSG_CHANNEL_FAILURE (channel " + id + ")");
1364    }
1365
1366    public void msgChannelOpenConfirmation(byte[] msg, int msglen) throws IOException JavaDoc
1367    {
1368        PacketChannelOpenConfirmation sm = new PacketChannelOpenConfirmation(msg, 0, msglen);
1369
1370        Channel c = getChannel(sm.recipientChannelID);
1371
1372        if (c == null)
1373            throw new IOException JavaDoc("Unexpected SSH_MSG_CHANNEL_OPEN_CONFIRMATION message for non-existent channel "
1374                    + sm.recipientChannelID);
1375
1376        synchronized (c)
1377        {
1378            if (c.state != Channel.STATE_OPENING)
1379                throw new IOException JavaDoc("Unexpected SSH_MSG_CHANNEL_OPEN_CONFIRMATION message for channel "
1380                        + sm.recipientChannelID);
1381
1382            c.remoteID = sm.senderChannelID;
1383            c.remoteWindow = sm.initialWindowSize & 0xFFFFffffL; /* convert UINT32 to long */
1384            c.remoteMaxPacketSize = sm.maxPacketSize;
1385            c.state = Channel.STATE_OPEN;
1386            c.notifyAll();
1387        }
1388
1389        if (log.isEnabled())
1390            log.log(50, "Got SSH_MSG_CHANNEL_OPEN_CONFIRMATION (channel " + sm.recipientChannelID + " / remote: "
1391                    + sm.senderChannelID + ")");
1392    }
1393
1394    public void msgChannelOpenFailure(byte[] msg, int msglen) throws IOException JavaDoc
1395    {
1396        if (msglen < 5)
1397            throw new IOException JavaDoc("SSH_MSG_CHANNEL_OPEN_FAILURE message has wrong size (" + msglen + ")");
1398
1399        TypesReader tr = new TypesReader(msg, 0, msglen);
1400
1401        tr.readByte(); // skip packet type
1402
int id = tr.readUINT32(); /* sender channel */
1403
1404        Channel c = getChannel(id);
1405
1406        if (c == null)
1407            throw new IOException JavaDoc("Unexpected SSH_MSG_CHANNEL_OPEN_FAILURE message for non-existent channel " + id);
1408
1409        int reasonCode = tr.readUINT32();
1410        String JavaDoc description = tr.readString("UTF-8");
1411
1412        String JavaDoc reasonCodeSymbolicName = null;
1413
1414        switch (reasonCode)
1415        {
1416        case 1:
1417            reasonCodeSymbolicName = "SSH_OPEN_ADMINISTRATIVELY_PROHIBITED";
1418            break;
1419        case 2:
1420            reasonCodeSymbolicName = "SSH_OPEN_CONNECT_FAILED";
1421            break;
1422        case 3:
1423            reasonCodeSymbolicName = "SSH_OPEN_UNKNOWN_CHANNEL_TYPE";
1424            break;
1425        case 4:
1426            reasonCodeSymbolicName = "SSH_OPEN_RESOURCE_SHORTAGE";
1427            break;
1428        default:
1429            reasonCodeSymbolicName = "UNKNOWN REASON CODE (" + reasonCode + ")";
1430        }
1431
1432        StringBuffer JavaDoc descriptionBuffer = new StringBuffer JavaDoc();
1433        descriptionBuffer.append(description);
1434
1435        for (int i = 0; i < descriptionBuffer.length(); i++)
1436        {
1437            char cc = descriptionBuffer.charAt(i);
1438
1439            if ((cc >= 32) && (cc <= 126))
1440                continue;
1441            descriptionBuffer.setCharAt(i, '\uFFFD');
1442        }
1443
1444        synchronized (c)
1445        {
1446            c.EOF = true;
1447            c.state = Channel.STATE_CLOSED;
1448            c.setReasonClosed("The server refused to open the channel (" + reasonCodeSymbolicName + ", '"
1449                    + descriptionBuffer.toString() + "')");
1450            c.notifyAll();
1451        }
1452
1453        if (log.isEnabled())
1454            log.log(50, "Got SSH_MSG_CHANNEL_OPEN_FAILURE (channel " + id + ")");
1455    }
1456
1457    public void msgGlobalRequest(byte[] msg, int msglen) throws IOException JavaDoc
1458    {
1459        /* Currently we do not support any kind of global request */
1460
1461        TypesReader tr = new TypesReader(msg, 0, msglen);
1462
1463        tr.readByte(); // skip packet type
1464
String JavaDoc requestName = tr.readString();
1465        boolean wantReply = tr.readBoolean();
1466
1467        if (wantReply)
1468        {
1469            byte[] reply_failure = new byte[1];
1470            reply_failure[0] = Packets.SSH_MSG_REQUEST_FAILURE;
1471
1472            tm.sendAsynchronousMessage(reply_failure);
1473        }
1474
1475        /* We do not clean up the requestName String - that is OK for debug */
1476
1477        if (log.isEnabled())
1478            log.log(80, "Got SSH_MSG_GLOBAL_REQUEST (" + requestName + ")");
1479    }
1480
1481    public void msgGlobalSuccess() throws IOException JavaDoc
1482    {
1483        synchronized (channels)
1484        {
1485            globalSuccessCounter++;
1486            channels.notifyAll();
1487        }
1488
1489        if (log.isEnabled())
1490            log.log(80, "Got SSH_MSG_REQUEST_SUCCESS");
1491    }
1492
1493    public void msgGlobalFailure() throws IOException JavaDoc
1494    {
1495        synchronized (channels)
1496        {
1497            globalFailedCounter++;
1498            channels.notifyAll();
1499        }
1500
1501        if (log.isEnabled())
1502            log.log(80, "Got SSH_MSG_REQUEST_FAILURE");
1503    }
1504
1505    public void handleMessage(byte[] msg, int msglen) throws IOException JavaDoc
1506    {
1507        if (msg == null)
1508        {
1509            if (log.isEnabled())
1510                log.log(50, "HandleMessage: got shutdown");
1511
1512            synchronized (listenerThreads)
1513            {
1514                for (int i = 0; i < listenerThreads.size(); i++)
1515                {
1516                    IChannelWorkerThread lat = (IChannelWorkerThread) listenerThreads.elementAt(i);
1517                    lat.stopWorking();
1518                }
1519                listenerThreadsAllowed = false;
1520            }
1521
1522            synchronized (channels)
1523            {
1524                shutdown = true;
1525
1526                for (int i = 0; i < channels.size(); i++)
1527                {
1528                    Channel c = (Channel) channels.elementAt(i);
1529                    synchronized (c)
1530                    {
1531                        c.EOF = true;
1532                        c.state = Channel.STATE_CLOSED;
1533                        c.setReasonClosed("The connection is being shutdown");
1534                        c.closeMessageRecv = true; /*
1535                         * You never know, perhaps
1536                         * we are waiting for a
1537                         * pending close message
1538                         * from the server...
1539                         */

1540                        c.notifyAll();
1541                    }
1542                }
1543                /* Works with J2ME */
1544                channels.setSize(0);
1545                channels.trimToSize();
1546                channels.notifyAll(); /* Notify global response waiters */
1547                return;
1548            }
1549        }
1550
1551        switch (msg[0])
1552        {
1553        case Packets.SSH_MSG_CHANNEL_OPEN_CONFIRMATION:
1554            msgChannelOpenConfirmation(msg, msglen);
1555            break;
1556        case Packets.SSH_MSG_CHANNEL_WINDOW_ADJUST:
1557            msgChannelWindowAdjust(msg, msglen);
1558            break;
1559        case Packets.SSH_MSG_CHANNEL_DATA:
1560            msgChannelData(msg, msglen);
1561            break;
1562        case Packets.SSH_MSG_CHANNEL_EXTENDED_DATA:
1563            msgChannelExtendedData(msg, msglen);
1564            break;
1565        case Packets.SSH_MSG_CHANNEL_REQUEST:
1566            msgChannelRequest(msg, msglen);
1567            break;
1568        case Packets.SSH_MSG_CHANNEL_EOF:
1569            msgChannelEOF(msg, msglen);
1570            break;
1571        case Packets.SSH_MSG_CHANNEL_OPEN:
1572            msgChannelOpen(msg, msglen);
1573            break;
1574        case Packets.SSH_MSG_CHANNEL_CLOSE:
1575            msgChannelClose(msg, msglen);
1576            break;
1577        case Packets.SSH_MSG_CHANNEL_SUCCESS:
1578            msgChannelSuccess(msg, msglen);
1579            break;
1580        case Packets.SSH_MSG_CHANNEL_FAILURE:
1581            msgChannelFailure(msg, msglen);
1582            break;
1583        case Packets.SSH_MSG_CHANNEL_OPEN_FAILURE:
1584            msgChannelOpenFailure(msg, msglen);
1585            break;
1586        case Packets.SSH_MSG_GLOBAL_REQUEST:
1587            msgGlobalRequest(msg, msglen);
1588            break;
1589        case Packets.SSH_MSG_REQUEST_SUCCESS:
1590            msgGlobalSuccess();
1591            break;
1592        case Packets.SSH_MSG_REQUEST_FAILURE:
1593            msgGlobalFailure();
1594            break;
1595        default:
1596            throw new IOException JavaDoc("Cannot handle unknown channel message " + (msg[0] & 0xff));
1597        }
1598    }
1599}
1600
Popular Tags