Channel.java
Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030 package com.jcraft.jsch;
00031
00032 import java.io.PipedInputStream;
00033 import java.io.PipedOutputStream;
00034 import java.io.InputStream;
00035 import java.io.OutputStream;
00036 import java.io.IOException;
00037
00049 public abstract class Channel implements Runnable{
00050
00051 static final int SSH_MSG_CHANNEL_OPEN_CONFIRMATION= 91;
00052 static final int SSH_MSG_CHANNEL_OPEN_FAILURE= 92;
00053 static final int SSH_MSG_CHANNEL_WINDOW_ADJUST= 93;
00054
00055 static final int SSH_OPEN_ADMINISTRATIVELY_PROHIBITED= 1;
00056 static final int SSH_OPEN_CONNECT_FAILED= 2;
00057 static final int SSH_OPEN_UNKNOWN_CHANNEL_TYPE= 3;
00058 static final int SSH_OPEN_RESOURCE_SHORTAGE= 4;
00059
00060 static int index=0;
00061 private static java.util.Vector pool=new java.util.Vector();
00067 static Channel getChannel(String type){
00068 if(type.equals("session")){
00069 return new ChannelSession();
00070 }
00071 if(type.equals("shell")){
00072 return new ChannelShell();
00073 }
00074 if(type.equals("exec")){
00075 return new ChannelExec();
00076 }
00077 if(type.equals("x11")){
00078 return new ChannelX11();
00079 }
00080 if(type.equals("auth-agent@openssh.com")){
00081 return new ChannelAgentForwarding();
00082 }
00083 if(type.equals("direct-tcpip")){
00084 return new ChannelDirectTCPIP();
00085 }
00086 if(type.equals("forwarded-tcpip")){
00087 return new ChannelForwardedTCPIP();
00088 }
00089 if(type.equals("sftp")){
00090 return new ChannelSftp();
00091 }
00092 if(type.equals("subsystem")){
00093 return new ChannelSubsystem();
00094 }
00095 return null;
00096 }
00097
00103 static Channel getChannel(int id, Session session){
00104 synchronized(pool){
00105 for(int i=0; i<pool.size(); i++){
00106 Channel c=(Channel)(pool.elementAt(i));
00107 if(c.id==id && c.session==session) return c;
00108 }
00109 }
00110 return null;
00111 }
00112
00116 static void del(Channel c){
00117 synchronized(pool){
00118 pool.removeElement(c);
00119 }
00120 }
00121
00122 int id;
00123 volatile int recipient=-1;
00124 protected byte[] type=Util.str2byte("foo");
00125 volatile int lwsize_max=0x100000;
00126 volatile int lwsize=lwsize_max;
00127 volatile int lmpsize=0x4000;
00128
00129 volatile long rwsize=0;
00130 volatile int rmpsize=0;
00131
00132 IO io=null;
00133 Thread thread=null;
00134
00135 volatile boolean eof_local=false;
00136 volatile boolean eof_remote=false;
00137
00138 volatile boolean close=false;
00139 volatile boolean connected=false;
00140 volatile boolean open_confirmation=false;
00141
00142 volatile int exitstatus=-1;
00143
00144 volatile int reply=0;
00145 volatile int connectTimeout=0;
00146
00147 private Session session;
00148
00149 int notifyme=0;
00150
00151 Channel(){
00152 synchronized(pool){
00153 id=index++;
00154 pool.addElement(this);
00155 }
00156 }
00157 synchronized void setRecipient(int foo){
00158 this.recipient=foo;
00159 if(notifyme>0)
00160 notifyAll();
00161 }
00162 int getRecipient(){
00163 return recipient;
00164 }
00165
00166 void init() throws JSchException {
00167 }
00168
00174 public void connect() throws JSchException{
00175 connect(0);
00176 }
00177
00191 public void connect(int connectTimeout) throws JSchException{
00192 Session _session=getSession();
00193 if(!_session.isConnected()){
00194 throw new JSchException("session is down");
00195 }
00196 this.connectTimeout=connectTimeout;
00197 try{
00198 Buffer buf=new Buffer(100);
00199 Packet packet=new Packet(buf);
00200
00201
00202
00203
00204
00205
00206 packet.reset();
00207 buf.putByte((byte)90);
00208 buf.putString(this.type);
00209 buf.putInt(this.id);
00210 buf.putInt(this.lwsize);
00211 buf.putInt(this.lmpsize);
00212 _session.write(packet);
00213 int retry=10;
00214 long start=System.currentTimeMillis();
00215 long timeout=connectTimeout;
00216 if(timeout!=0L) retry = 1;
00217 synchronized(this){
00218 while(this.getRecipient()==-1 &&
00219 _session.isConnected() &&
00220 retry>0){
00221 if(timeout>0L){
00222 if((System.currentTimeMillis()-start)>timeout){
00223 retry=0;
00224 continue;
00225 }
00226 }
00227 try{
00228 long t = timeout==0L ? 5000L : timeout;
00229 this.notifyme=1;
00230 wait(t);
00231 }
00232 catch(java.lang.InterruptedException e){
00233 }
00234 finally{
00235 this.notifyme=0;
00236 }
00237 retry--;
00238 }
00239 }
00240 if(!_session.isConnected()){
00241 throw new JSchException("session is down");
00242 }
00243 if(this.getRecipient()==-1){
00244 throw new JSchException("channel is not opened.");
00245 }
00246 if(this.open_confirmation==false){
00247 throw new JSchException("channel is not opened.");
00248 }
00249
00250 connected=true;
00251 start();
00252 }
00253 catch(Exception e){
00254 connected=false;
00255 disconnect();
00256 if(e instanceof JSchException)
00257 throw (JSchException)e;
00258 throw new JSchException(e.toString(), e);
00259 }
00260 }
00261
00269 public void setXForwarding(boolean foo){
00270 }
00271
00280 public void start() throws JSchException{}
00281
00287 public boolean isEOF() {return eof_remote;}
00288
00289 void getData(Buffer buf){
00290 setRecipient(buf.getInt());
00291 setRemoteWindowSize(buf.getUInt());
00292 setRemotePacketSize(buf.getInt());
00293 }
00294
00302 public void setInputStream(InputStream in){
00303 io.setInputStream(in, false);
00304 }
00313 public void setInputStream(InputStream in, boolean dontclose){
00314 io.setInputStream(in, dontclose);
00315 }
00324 public void setOutputStream(OutputStream out){
00325 io.setOutputStream(out, false);
00326 }
00336 public void setOutputStream(OutputStream out, boolean dontclose){
00337 io.setOutputStream(out, dontclose);
00338 }
00339
00355 public void setExtOutputStream(OutputStream out){
00356 io.setExtOutputStream(out, false);
00357 }
00358
00376 public void setExtOutputStream(OutputStream out, boolean dontclose){
00377 io.setExtOutputStream(out, dontclose);
00378 }
00379
00388 public InputStream getInputStream() throws IOException {
00389 PipedInputStream in=
00390 new MyPipedInputStream(
00391 32*1024
00392 );
00393 io.setOutputStream(new PassiveOutputStream(in), false);
00394 return in;
00395 }
00396
00406 public InputStream getExtInputStream() throws IOException {
00407 PipedInputStream in=
00408 new MyPipedInputStream(
00409 32*1024
00410 );
00411 io.setExtOutputStream(new PassiveOutputStream(in), false);
00412 return in;
00413 }
00414
00424 public OutputStream getOutputStream() throws IOException {
00425
00426
00427
00428
00429
00430
00431
00432
00433 final Channel channel=this;
00434 OutputStream out=new OutputStream(){
00435 private int dataLen=0;
00436 private Buffer buffer=null;
00437 private Packet packet=null;
00438 private boolean closed=false;
00439 private synchronized void init() throws java.io.IOException{
00440 buffer=new Buffer(rmpsize);
00441 packet=new Packet(buffer);
00442
00443 byte[] _buf=buffer.buffer;
00444 if(_buf.length-(14+0)-Session.buffer_margin<=0){
00445 buffer=null;
00446 packet=null;
00447 throw new IOException("failed to initialize the channel.");
00448 }
00449
00450 }
00451 byte[] b=new byte[1];
00452 public void write(int w) throws java.io.IOException{
00453 b[0]=(byte)w;
00454 write(b, 0, 1);
00455 }
00456 public void write(byte[] buf, int s, int l) throws java.io.IOException{
00457 if(packet==null){
00458 init();
00459 }
00460
00461 if(closed){
00462 throw new java.io.IOException("Already closed");
00463 }
00464
00465 byte[] _buf=buffer.buffer;
00466 int _bufl=_buf.length;
00467 while(l>0){
00468 int _l=l;
00469 if(l>_bufl-(14+dataLen)-Session.buffer_margin){
00470 _l=_bufl-(14+dataLen)-Session.buffer_margin;
00471 }
00472
00473 if(_l<=0){
00474 flush();
00475 continue;
00476 }
00477
00478 System.arraycopy(buf, s, _buf, 14+dataLen, _l);
00479 dataLen+=_l;
00480 s+=_l;
00481 l-=_l;
00482 }
00483 }
00484
00485 public void flush() throws java.io.IOException{
00486 if(closed){
00487 throw new java.io.IOException("Already closed");
00488 }
00489 if(dataLen==0)
00490 return;
00491 packet.reset();
00492 buffer.putByte((byte)Session.SSH_MSG_CHANNEL_DATA);
00493 buffer.putInt(recipient);
00494 buffer.putInt(dataLen);
00495 buffer.skip(dataLen);
00496 try{
00497 int foo=dataLen;
00498 dataLen=0;
00499 getSession().write(packet, channel, foo);
00500 }
00501 catch(Exception e){
00502 close();
00503 throw new java.io.IOException(e.toString());
00504 }
00505
00506 }
00507 public void close() throws java.io.IOException{
00508 if(packet==null){
00509 try{
00510 init();
00511 }
00512 catch(java.io.IOException e){
00513
00514 return;
00515 }
00516 }
00517 if(closed){
00518 return;
00519 }
00520 if(dataLen>0){
00521 flush();
00522 }
00523 channel.eof();
00524 closed=true;
00525 }
00526 };
00527 return out;
00528 }
00529
00530 class MyPipedInputStream extends PipedInputStream{
00531 MyPipedInputStream() throws IOException{ super(); }
00532 MyPipedInputStream(int size) throws IOException{
00533 super();
00534 buffer=new byte[size];
00535 }
00536 MyPipedInputStream(PipedOutputStream out) throws IOException{ super(out); }
00537 MyPipedInputStream(PipedOutputStream out, int size) throws IOException{
00538 super(out);
00539 buffer=new byte[size];
00540 }
00541
00542
00543
00544
00545
00546
00547
00548 public synchronized void updateReadSide() throws IOException {
00549 if(available() != 0){
00550 return;
00551 }
00552 in = 0;
00553 out = 0;
00554 buffer[in++] = 0;
00555 read();
00556 }
00557 }
00558 void setLocalWindowSizeMax(int foo){ this.lwsize_max=foo; }
00559 void setLocalWindowSize(int foo){ this.lwsize=foo; }
00560 void setLocalPacketSize(int foo){ this.lmpsize=foo; }
00561 synchronized void setRemoteWindowSize(long foo){ this.rwsize=foo; }
00562 synchronized void addRemoteWindowSize(int foo){
00563 this.rwsize+=foo;
00564 if(notifyme>0)
00565 notifyAll();
00566 }
00567 void setRemotePacketSize(int foo){ this.rmpsize=foo; }
00568
00574 public void run(){
00575 }
00576
00577 void write(byte[] foo) throws IOException {
00578 write(foo, 0, foo.length);
00579 }
00580 void write(byte[] foo, int s, int l) throws IOException {
00581 try{
00582 io.put(foo, s, l);
00583 }catch(NullPointerException e){}
00584 }
00585 void write_ext(byte[] foo, int s, int l) throws IOException {
00586 try{
00587 io.put_ext(foo, s, l);
00588 }catch(NullPointerException e){}
00589 }
00590
00597 void eof_remote(){
00598 eof_remote=true;
00599 try{
00600 io.out_close();
00601 }
00602 catch(NullPointerException e){}
00603 }
00604
00605 void eof(){
00606 if(eof_local)return;
00607 eof_local=true;
00608
00609 try{
00610 Buffer buf=new Buffer(100);
00611 Packet packet=new Packet(buf);
00612 packet.reset();
00613 buf.putByte((byte)Session.SSH_MSG_CHANNEL_EOF);
00614 buf.putInt(getRecipient());
00615 synchronized(this){
00616 if(!close)
00617 getSession().write(packet);
00618 }
00619 }
00620 catch(Exception e){
00621
00622
00623 }
00624
00625
00626
00627 }
00628
00629
00630
00631
00632
00633
00634
00635
00636
00637
00638
00639
00640
00641
00642
00643
00644
00645
00646
00647
00648
00649
00650
00651
00652
00653
00654
00655
00656
00657
00658
00659
00660
00661
00662
00663
00664
00665 void close(){
00666 if(close)return;
00667 close=true;
00668 eof_local=eof_remote=true;
00669
00670 try{
00671 Buffer buf=new Buffer(100);
00672 Packet packet=new Packet(buf);
00673 packet.reset();
00674 buf.putByte((byte)Session.SSH_MSG_CHANNEL_CLOSE);
00675 buf.putInt(getRecipient());
00676 synchronized(this){
00677 getSession().write(packet);
00678 }
00679 }
00680 catch(Exception e){
00681
00682 }
00683 }
00688 public boolean isClosed(){
00689 return close;
00690 }
00691
00695 static void disconnect(Session session){
00696 Channel[] channels=null;
00697 int count=0;
00698 synchronized(pool){
00699 channels=new Channel[pool.size()];
00700 for(int i=0; i<pool.size(); i++){
00701 try{
00702 Channel c=((Channel)(pool.elementAt(i)));
00703 if(c.session==session){
00704 channels[count++]=c;
00705 }
00706 }
00707 catch(Exception e){
00708 }
00709 }
00710 }
00711 for(int i=0; i<count; i++){
00712 channels[i].disconnect();
00713 }
00714 }
00715
00719 public void disconnect(){
00720
00721
00722
00723 try{
00724
00725 synchronized(this){
00726 if(!connected){
00727 return;
00728 }
00729 connected=false;
00730 }
00731
00732 close();
00733
00734 eof_remote=eof_local=true;
00735
00736 thread=null;
00737
00738 try{
00739 if(io!=null){
00740 io.close();
00741 }
00742 }
00743 catch(Exception e){
00744
00745 }
00746
00747 }
00748 finally{
00749 Channel.del(this);
00750 }
00751 }
00752
00753
00759 public boolean isConnected(){
00760 Session _session=this.session;
00761 if(_session!=null){
00762 return _session.isConnected() && connected;
00763 }
00764 return false;
00765 }
00766
00775 public void sendSignal(String signal) throws Exception {
00776 RequestSignal request=new RequestSignal();
00777 request.setSignal(signal);
00778 request.request(getSession(), this);
00779 }
00780
00781
00782
00783
00784
00785
00786
00787
00788
00789
00790
00791
00792
00793 class PassiveInputStream extends MyPipedInputStream{
00794 PipedOutputStream out;
00795 PassiveInputStream(PipedOutputStream out, int size) throws IOException{
00796 super(out, size);
00797 this.out=out;
00798 }
00799 PassiveInputStream(PipedOutputStream out) throws IOException{
00800 super(out);
00801 this.out=out;
00802 }
00803 public void close() throws IOException{
00804 if(out!=null){
00805 this.out.close();
00806 }
00807 out=null;
00808 }
00809 }
00810 class PassiveOutputStream extends PipedOutputStream{
00811 PassiveOutputStream(PipedInputStream in) throws IOException{
00812 super(in);
00813 }
00814 }
00815
00816 void setExitStatus(int status){ exitstatus=status; }
00830 public int getExitStatus(){ return exitstatus; }
00831
00832 void setSession(Session session){
00833 this.session=session;
00834 }
00835
00842 public Session getSession() throws JSchException{
00843 Session _session=session;
00844 if(_session==null){
00845 throw new JSchException("session is not available");
00846 }
00847 return _session;
00848 }
00849
00853 public int getId(){ return id; }
00854
00855
00859 protected void sendOpenConfirmation() throws Exception{
00860 Buffer buf=new Buffer(100);
00861 Packet packet=new Packet(buf);
00862 packet.reset();
00863 buf.putByte((byte)SSH_MSG_CHANNEL_OPEN_CONFIRMATION);
00864 buf.putInt(getRecipient());
00865 buf.putInt(id);
00866 buf.putInt(lwsize);
00867 buf.putInt(lmpsize);
00868 getSession().write(packet);
00869 }
00870
00875 protected void sendOpenFailure(int reasoncode){
00876 try{
00877 Buffer buf=new Buffer(100);
00878 Packet packet=new Packet(buf);
00879 packet.reset();
00880 buf.putByte((byte)SSH_MSG_CHANNEL_OPEN_FAILURE);
00881 buf.putInt(getRecipient());
00882 buf.putInt(reasoncode);
00883 buf.putString(Util.str2byte("open failed"));
00884 buf.putString(Util.empty);
00885 getSession().write(packet);
00886 }
00887 catch(Exception e){
00888 }
00889 }
00890 }