KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > jcraft > jsch > Channel


1 /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
2 /*
3 Copyright (c) 2002,2003,2004,2005,2006 ymnk, JCraft,Inc. All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions are met:
7
8   1. Redistributions of source code must retain the above copyright notice,
9      this list of conditions and the following disclaimer.
10
11   2. Redistributions in binary form must reproduce the above copyright
12      notice, this list of conditions and the following disclaimer in
13      the documentation and/or other materials provided with the distribution.
14
15   3. The names of the authors may not be used to endorse or promote products
16      derived from this software without specific prior written permission.
17
18 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
19 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
20 FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
21 INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
22 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
24 OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25 LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26 NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
27 EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */

29
30 package com.jcraft.jsch;
31
32 import java.io.PipedInputStream JavaDoc;
33 import java.io.PipedOutputStream JavaDoc;
34 import java.io.InputStream JavaDoc;
35 import java.io.OutputStream JavaDoc;
36 import java.io.IOException JavaDoc;
37
38
39 public abstract class Channel implements Runnable JavaDoc{
40
41   static final int SSH_MSG_CHANNEL_OPEN_CONFIRMATION= 91;
42   static final int SSH_MSG_CHANNEL_OPEN_FAILURE= 92;
43
44   static final int SSH_OPEN_ADMINISTRATIVELY_PROHIBITED= 1;
45   static final int SSH_OPEN_CONNECT_FAILED= 2;
46   static final int SSH_OPEN_UNKNOWN_CHANNEL_TYPE= 3;
47   static final int SSH_OPEN_RESOURCE_SHORTAGE= 4;
48
49   static int index=0;
50   private static java.util.Vector JavaDoc pool=new java.util.Vector JavaDoc();
51   static Channel getChannel(String JavaDoc type){
52     if(type.equals("session")){
53       return new ChannelSession();
54     }
55     if(type.equals("shell")){
56       return new ChannelShell();
57     }
58     if(type.equals("exec")){
59       return new ChannelExec();
60     }
61     if(type.equals("x11")){
62       return new ChannelX11();
63     }
64     if(type.equals("auth-agent@openssh.com")){
65       return new ChannelAgentForwarding();
66     }
67     if(type.equals("direct-tcpip")){
68       return new ChannelDirectTCPIP();
69     }
70     if(type.equals("forwarded-tcpip")){
71       return new ChannelForwardedTCPIP();
72     }
73     if(type.equals("sftp")){
74       return new ChannelSftp();
75     }
76     if(type.equals("subsystem")){
77       return new ChannelSubsystem();
78     }
79     return null;
80   }
81   static Channel getChannel(int id, Session session){
82     synchronized(pool){
83       for(int i=0; i<pool.size(); i++){
84     Channel c=(Channel)(pool.elementAt(i));
85     if(c.id==id && c.session==session) return c;
86       }
87     }
88     return null;
89   }
90   static void del(Channel c){
91     synchronized(pool){
92       pool.removeElement(c);
93     }
94   }
95
96   int id;
97   int recipient=-1;
98   byte[] type="foo".getBytes();
99   int lwsize_max=0x100000;
100 //int lwsize_max=0x20000; // 32*1024*4
101
int lwsize=lwsize_max; // local initial window size
102
int lmpsize=0x4000; // local maximum packet size
103
//int lmpsize=0x8000; // local maximum packet size
104

105   int rwsize=0; // remote initial window size
106
int rmpsize=0; // remote maximum packet size
107

108   IO io=null;
109   Thread JavaDoc thread=null;
110
111   boolean eof_local=false;
112   boolean eof_remote=false;
113
114   boolean close=false;
115   boolean connected=false;
116
117   int exitstatus=-1;
118
119   int reply=0;
120   int connectTimeout=0;
121
122   Session session;
123
124   Channel(){
125     synchronized(pool){
126       id=index++;
127       pool.addElement(this);
128     }
129   }
130   void setRecipient(int foo){
131     this.recipient=foo;
132   }
133   int getRecipient(){
134     return recipient;
135   }
136
137   void init(){
138   }
139
140   public void connect() throws JSchException{
141     connect(0);
142   }
143
144   public void connect(int connectTimeout) throws JSchException{
145     if(!session.isConnected()){
146       throw new JSchException("session is down");
147     }
148     this.connectTimeout=connectTimeout;
149     try{
150       Buffer buf=new Buffer(100);
151       Packet packet=new Packet(buf);
152       // send
153
// byte SSH_MSG_CHANNEL_OPEN(90)
154
// string channel type //
155
// uint32 sender channel // 0
156
// uint32 initial window size // 0x100000(65536)
157
// uint32 maxmum packet size // 0x4000(16384)
158
packet.reset();
159       buf.putByte((byte)90);
160       buf.putString(this.type);
161       buf.putInt(this.id);
162       buf.putInt(this.lwsize);
163       buf.putInt(this.lmpsize);
164       session.write(packet);
165       int retry=1000;
166       long start=System.currentTimeMillis();
167       long timeout=connectTimeout;
168       while(this.getRecipient()==-1 &&
169         session.isConnected() &&
170         retry>0){
171         if(timeout>0L){
172           if((System.currentTimeMillis()-start)>timeout){
173             retry=0;
174             continue;
175           }
176         }
177     try{Thread.sleep(50);}catch(Exception JavaDoc ee){}
178     retry--;
179       }
180       if(!session.isConnected()){
181     throw new JSchException("session is down");
182       }
183       if(retry==0){
184         throw new JSchException("channel is not opened.");
185       }
186       connected=true;
187       start();
188     }
189     catch(Exception JavaDoc e){
190       connected=false;
191       if(e instanceof JSchException) throw (JSchException)e;
192     }
193   }
194
195   public void setXForwarding(boolean foo){
196   }
197
198   public void start() throws JSchException{}
199
200   public boolean isEOF() {return eof_remote;}
201
202   void getData(Buffer buf){
203     setRecipient(buf.getInt());
204     setRemoteWindowSize(buf.getInt());
205     setRemotePacketSize(buf.getInt());
206   }
207
208   public void setInputStream(InputStream JavaDoc in){
209     io.setInputStream(in, false);
210   }
211   public void setInputStream(InputStream JavaDoc in, boolean dontclose){
212     io.setInputStream(in, dontclose);
213   }
214   public void setOutputStream(OutputStream JavaDoc out){
215     io.setOutputStream(out, false);
216   }
217   public void setOutputStream(OutputStream JavaDoc out, boolean dontclose){
218     io.setOutputStream(out, dontclose);
219   }
220   public void setExtOutputStream(OutputStream JavaDoc out){
221     io.setExtOutputStream(out, false);
222   }
223   public void setExtOutputStream(OutputStream JavaDoc out, boolean dontclose){
224     io.setExtOutputStream(out, dontclose);
225   }
226   public InputStream JavaDoc getInputStream() throws IOException JavaDoc {
227     PipedInputStream JavaDoc in=
228       new MyPipedInputStream(
229                              32*1024 // this value should be customizable.
230
);
231     io.setOutputStream(new PassiveOutputStream(in), false);
232     return in;
233   }
234   public InputStream JavaDoc getExtInputStream() throws IOException JavaDoc {
235     PipedInputStream JavaDoc in=
236       new MyPipedInputStream(
237                              32*1024 // this value should be customizable.
238
);
239     io.setExtOutputStream(new PassiveOutputStream(in), false);
240     return in;
241   }
242   public OutputStream JavaDoc getOutputStream() throws IOException JavaDoc {
243     /*
244     PipedOutputStream out=new PipedOutputStream();
245     io.setInputStream(new PassiveInputStream(out
246                                              , 32*1024
247                                              ), false);
248     return out;
249     */

250
251     final Channel channel=this;
252     OutputStream JavaDoc out=new OutputStream JavaDoc(){
253         private int dataLen=0;
254         private Buffer buffer=null;
255         private Packet packet=null;
256         private boolean closed=false;
257         private void init(){
258           buffer=new Buffer(rmpsize);
259           packet=new Packet(buffer);
260         }
261         byte[] b=new byte[1];
262         public void write(int w) throws java.io.IOException JavaDoc{
263           b[0]=(byte)w;
264           write(b, 0, 1);
265         }
266         public void write(byte[] buf, int s, int l) throws java.io.IOException JavaDoc{
267           if(packet==null){
268             init();
269           }
270
271           if(closed){
272             throw new java.io.IOException JavaDoc("Already closed");
273           }
274
275           byte[] _buf=buffer.buffer;
276           int _bufl=_buf.length;
277           while(l>0){
278             int _l=l;
279             if(l>_bufl-(14+dataLen)-32-20){
280               _l=_bufl-(14+dataLen)-32-20;
281             }
282
283             if(_l<=0){
284               flush();
285               continue;
286             }
287
288             System.arraycopy(buf, s, _buf, 14+dataLen, _l);
289             dataLen+=_l;
290             s+=_l;
291             l-=_l;
292           }
293         }
294
295         public void flush() throws java.io.IOException JavaDoc{
296           if(closed){
297             throw new java.io.IOException JavaDoc("Already closed");
298           }
299           if(dataLen==0)
300             return;
301           packet.reset();
302           buffer.putByte((byte)Session.SSH_MSG_CHANNEL_DATA);
303           buffer.putInt(recipient);
304           buffer.putInt(dataLen);
305           buffer.skip(dataLen);
306           try{
307             int foo=dataLen;
308             dataLen=0;
309             session.write(packet, channel, foo);
310           }
311           catch(Exception JavaDoc e){
312             close();
313             throw new java.io.IOException JavaDoc(e.toString());
314           }
315
316         }
317         public void close() throws java.io.IOException JavaDoc{
318           if(packet==null){
319             init();
320           }
321           if(closed){
322             return;
323           }
324           if(dataLen>0){
325             flush();
326           }
327           channel.eof();
328           closed=true;
329         }
330       };
331     return out;
332
333   }
334   class MyPipedInputStream extends PipedInputStream JavaDoc{
335     MyPipedInputStream() throws IOException JavaDoc{ super(); }
336     MyPipedInputStream(int size) throws IOException JavaDoc{
337       super();
338       buffer=new byte[size];
339     }
340     MyPipedInputStream(PipedOutputStream JavaDoc out) throws IOException JavaDoc{ super(out); }
341     MyPipedInputStream(PipedOutputStream JavaDoc out, int size) throws IOException JavaDoc{
342       super(out);
343       buffer=new byte[size];
344     }
345   }
346   void setLocalWindowSizeMax(int foo){ this.lwsize_max=foo; }
347   void setLocalWindowSize(int foo){ this.lwsize=foo; }
348   void setLocalPacketSize(int foo){ this.lmpsize=foo; }
349   synchronized void setRemoteWindowSize(int foo){ this.rwsize=foo; }
350   synchronized void addRemoteWindowSize(int foo){ this.rwsize+=foo; }
351   void setRemotePacketSize(int foo){ this.rmpsize=foo; }
352
353   public void run(){
354   }
355
356   void write(byte[] foo) throws IOException JavaDoc {
357     write(foo, 0, foo.length);
358   }
359   void write(byte[] foo, int s, int l) throws IOException JavaDoc {
360     try{
361 // if(io.out!=null)
362
io.put(foo, s, l);
363     }catch(NullPointerException JavaDoc e){}
364   }
365   void write_ext(byte[] foo, int s, int l) throws IOException JavaDoc {
366     try{
367 // if(io.out_ext!=null)
368
io.put_ext(foo, s, l);
369     }catch(NullPointerException JavaDoc e){}
370   }
371
372   void eof_remote(){
373     eof_remote=true;
374     try{
375       if(io.out!=null){
376         io.out.close();
377         io.out=null;
378       }
379     }
380     catch(NullPointerException JavaDoc e){}
381     catch(IOException JavaDoc e){}
382   }
383
384   void eof(){
385 //System.err.println("EOF!!!! "+this);
386
//Thread.dumpStack();
387
if(close)return;
388     if(eof_local)return;
389     eof_local=true;
390     //close=eof;
391
try{
392       Buffer buf=new Buffer(100);
393       Packet packet=new Packet(buf);
394       packet.reset();
395       buf.putByte((byte)Session.SSH_MSG_CHANNEL_EOF);
396       buf.putInt(getRecipient());
397       session.write(packet);
398     }
399     catch(Exception JavaDoc e){
400       //System.err.println("Channel.eof");
401
//e.printStackTrace();
402
}
403     /*
404     if(!isConnected()){ disconnect(); }
405     */

406   }
407
408   /*
409   http://www1.ietf.org/internet-drafts/draft-ietf-secsh-connect-24.txt
410
411 5.3 Closing a Channel
412   When a party will no longer send more data to a channel, it SHOULD
413    send SSH_MSG_CHANNEL_EOF.
414
415             byte SSH_MSG_CHANNEL_EOF
416             uint32 recipient_channel
417
418   No explicit response is sent to this message. However, the
419    application may send EOF to whatever is at the other end of the
420   channel. Note that the channel remains open after this message, and
421    more data may still be sent in the other direction. This message
422    does not consume window space and can be sent even if no window space
423    is available.
424
425      When either party wishes to terminate the channel, it sends
426      SSH_MSG_CHANNEL_CLOSE. Upon receiving this message, a party MUST
427    send back a SSH_MSG_CHANNEL_CLOSE unless it has already sent this
428    message for the channel. The channel is considered closed for a
429      party when it has both sent and received SSH_MSG_CHANNEL_CLOSE, and
430    the party may then reuse the channel number. A party MAY send
431    SSH_MSG_CHANNEL_CLOSE without having sent or received
432    SSH_MSG_CHANNEL_EOF.
433
434             byte SSH_MSG_CHANNEL_CLOSE
435             uint32 recipient_channel
436
437    This message does not consume window space and can be sent even if no
438    window space is available.
439
440    It is recommended that any data sent before this message is delivered
441      to the actual destination, if possible.
442   */

443
444   void close(){
445     //System.err.println("close!!!!");
446
if(close)return;
447     close=true;
448
449     eof_local=eof_remote=true;
450
451     try{
452       Buffer buf=new Buffer(100);
453       Packet packet=new Packet(buf);
454       packet.reset();
455       buf.putByte((byte)Session.SSH_MSG_CHANNEL_CLOSE);
456       buf.putInt(getRecipient());
457       session.write(packet);
458     }
459     catch(Exception JavaDoc e){
460       //e.printStackTrace();
461
}
462   }
463   public boolean isClosed(){
464     return close;
465   }
466   static void disconnect(Session session){
467     Channel[] channels=null;
468     int count=0;
469     synchronized(pool){
470       channels=new Channel[pool.size()];
471       for(int i=0; i<pool.size(); i++){
472     try{
473       Channel c=((Channel)(pool.elementAt(i)));
474       if(c.session==session){
475         channels[count++]=c;
476       }
477     }
478     catch(Exception JavaDoc e){
479     }
480       }
481     }
482     for(int i=0; i<count; i++){
483       channels[i].disconnect();
484     }
485   }
486
487   public void disconnect(){
488     //System.err.println(this+":disconnect "+io+" "+connected);
489
//Thread.dumpStack();
490

491     synchronized(this){
492       if(!connected){
493         return;
494       }
495       connected=false;
496     }
497
498     close();
499
500     eof_remote=eof_local=true;
501
502     thread=null;
503
504     try{
505       if(io!=null){
506         io.close();
507       }
508     }
509     catch(Exception JavaDoc e){
510       //e.printStackTrace();
511
}
512     io=null;
513     Channel.del(this);
514   }
515
516   public boolean isConnected(){
517     if(this.session!=null){
518       return session.isConnected() && connected;
519     }
520     return false;
521   }
522
523   public void sendSignal(String JavaDoc foo) throws Exception JavaDoc {
524     RequestSignal request=new RequestSignal();
525     request.setSignal(foo);
526     request.request(session, this);
527   }
528
529 // public String toString(){
530
// return "Channel: type="+new String(type)+",id="+id+",recipient="+recipient+",window_size="+window_size+",packet_size="+packet_size;
531
// }
532

533 /*
534   class OutputThread extends Thread{
535     Channel c;
536     OutputThread(Channel c){ this.c=c;}
537     public void run(){c.output_thread();}
538   }
539 */

540
541   class PassiveInputStream extends MyPipedInputStream{
542     PipedOutputStream JavaDoc out;
543     PassiveInputStream(PipedOutputStream JavaDoc out, int size) throws IOException JavaDoc{
544       super(out, size);
545       this.out=out;
546     }
547     PassiveInputStream(PipedOutputStream JavaDoc out) throws IOException JavaDoc{
548       super(out);
549       this.out=out;
550     }
551     public void close() throws IOException JavaDoc{
552       if(out!=null){
553         this.out.close();
554       }
555       out=null;
556     }
557   }
558   class PassiveOutputStream extends PipedOutputStream JavaDoc{
559     PassiveOutputStream(PipedInputStream JavaDoc in) throws IOException JavaDoc{
560       super(in);
561     }
562   }
563
564   void setExitStatus(int foo){ exitstatus=foo; }
565   public int getExitStatus(){ return exitstatus; }
566
567   void setSession(Session session){
568     this.session=session;
569   }
570   public Session getSession(){ return session; }
571   public int getId(){ return id; }
572   //public int getRecipientId(){ return getRecipient(); }
573

574   protected void sendOpenConfirmation() throws Exception JavaDoc{
575     Buffer buf=new Buffer(100);
576     Packet packet=new Packet(buf);
577     packet.reset();
578     buf.putByte((byte)SSH_MSG_CHANNEL_OPEN_CONFIRMATION);
579     buf.putInt(getRecipient());
580     buf.putInt(id);
581     buf.putInt(lwsize);
582     buf.putInt(lmpsize);
583     session.write(packet);
584   }
585
586   protected void sendOpenFailure(int reasoncode){
587     try{
588       Buffer buf=new Buffer(100);
589       Packet packet=new Packet(buf);
590       packet.reset();
591       buf.putByte((byte)SSH_MSG_CHANNEL_OPEN_FAILURE);
592       buf.putInt(getRecipient());
593       buf.putInt(reasoncode);
594       buf.putString("open failed".getBytes());
595       buf.putString("".getBytes());
596       session.write(packet);
597     }
598     catch(Exception JavaDoc e){
599     }
600   }
601 }
602
Popular Tags