public void close()
 {
     try
     {
         if(ins!=null)ins.close();
         if(outs!=null)outs.close();
         if(socket!=null)socket.close();
     }
     catch(Exception e)
     {
     }
     ins=null;
     outs=null;
     socket=null;
 }
        public void connect(SocketFactory socket_factory, String host, int port, int timeout)
        {
            try
            {
                if(socket_factory==null)
                {
                    socket=Util.createSocket(proxy_host, proxy_port, timeout);
                    ins= new JStream(socket.getInputStream());
                    outs=new JStream(socket.getOutputStream());
                }
                else
                {
                    socket=socket_factory.createSocket(proxy_host, proxy_port);
                    ins=new JStream(socket_factory.getInputStream(socket));
                    outs=new JStream(socket_factory.getOutputStream(socket));
                }
                if(timeout>0)
                {
                    socket.setSoTimeout(timeout);
                }
                socket.setTcpNoDelay(true);

                outs.write(new String("CONNECT "+host+":"+port+" HTTP/1.0\r\n").getBytes());

                if(user!=null && passwd!=null)
                {
                    byte[] _code=(user+":"+passwd).getBytes();
                    _code=Util.toBase64(_code, 0, _code.Length);
                    outs.write(new String("Proxy-Authorization: Basic ").getBytes());
                    outs.write(_code);
                    outs.write(new String("\r\n").getBytes());
                }

                outs.write(new String("\r\n").getBytes());
                outs.flush();

                int foo=0;

                StringBuffer sb=new StringBuffer();
                while(foo>=0)
                {
                    foo=ins.read(); if(foo!=13){sb.append((char)foo);  continue;}
                    foo=ins.read(); if(foo!=10){continue;}
                    break;
                }
                if(foo<0)
                {
                    throw new System.IO.IOException();
                }

                String response=sb.toString();
                String reason="Unknow reason";
                int code=-1;
                try
                {
                    foo=response.indexOf(' ');
                    int bar=response.indexOf(' ', foo+1);
                    code=Integer.parseInt(response.substring(foo+1, bar));
                    reason=response.substring(bar+1);
                }
                catch(Exception e)
                {
                }
                if(code!=200)
                {
                    throw new System.IO.IOException("proxy error: "+reason);
                }

                /*
                while(foo>=0){
                  foo=in.read(); if(foo!=13) continue;
                  foo=in.read(); if(foo!=10) continue;
                  foo=in.read(); if(foo!=13) continue;
                  foo=in.read(); if(foo!=10) continue;
                  break;
                }
                */

                int count=0;
                while(true)
                {
                    count=0;
                    while(foo>=0)
                    {
                        foo=ins.read(); if(foo!=13){count++;  continue;}
                        foo=ins.read(); if(foo!=10){continue;}
                        break;
                    }
                    if(foo<0)
                    {
                        throw new System.IO.IOException();
                    }
                    if(count==0)break;
                }
            }
            catch(RuntimeException e)
            {
                throw e;
            }
            catch(Exception e)
            {
                try{ if(socket!=null)socket.close(); }
                catch(Exception eee)
                {
                }
                String message="ProxyHTTP: "+e.toString();
                throw e;
            }
        }
        /*
        public void finalize() throws Throwable{
          disconnect();
          jsch=null;
        }
        */
        public void disconnect()
        {
            if(!_isConnected) return;

            //System.Console.WriteLine(this+": disconnect");
            //Thread.dumpStack();
            /*
            for(int i=0; i<Channel.pool.size(); i++){
              try{
                Channel c=((Channel)(Channel.pool.elementAt(i)));
            if(c.session==this) c.eof();
              }
              catch(Exception e){
              }
            }
            */

            Channel.disconnect(this);

            _isConnected=false;

            PortWatcher.delPort(this);
            ChannelForwardedTCPIP.delPort(this);

            if (connectThread != null)
            {
                lock (connectThread)
                {
                    connectThread.yield();
                    connectThread.interrupt();
                    connectThread = null;
                }
            }
            thread=null;
            try
            {
                if(io!=null)
                {
                    if(io.ins!=null) io.ins.Close();
                    if(io.outs!=null) io.outs.Close();
                    if(io.outs_ext!=null) io.outs_ext.Close();
                }
                if(proxy==null)
                {
                    if(socket!=null)
                        socket.close();
                }
                else
                {
                    lock(proxy)
                    {
                        proxy.close();
                    }
                    proxy=null;
                }
            }
            catch(Exception e)
            {
                //      e.printStackTrace();
            }
            io=null;
            socket=null;
            //    lock(jsch.pool){
            //      jsch.pool.removeElement(this);
            //    }

            jsch.removeSession(this);

            //System.gc();
        }
        public void connect(int connectTimeout)
        {
            if(_isConnected)
            {
                throw new JSchException("session is already connected");
            }
            io=new IO();
            if(random==null)
            {
                try
                {
                    Class c=Class.forName(getConfig("random"));
                    random=(Random)(c.newInstance());
                }
                catch(Exception e)
                {
                    System.Console.Error.WriteLine("connect: random "+e);
                }
            }
            Packet.setRandom(random);

            try
            {
                int i, j;
                int pad=0;

                if(proxy==null)
                {
                    proxy=jsch.getProxy(host);
                    if(proxy!=null)
                    {
                        lock(proxy)
                        {
                            proxy.close();
                        }
                    }
                }

                if(proxy==null)
                {
                    Stream In;
                    Stream Out;
                    if(socket_factory==null)
                    {
                        socket=Util.createSocket(host, port, connectTimeout);
                        In=socket.getInputStream();
                        Out=socket.getOutputStream();
                    }
                    else
                    {
                        socket=socket_factory.createSocket(host, port);
                        In=socket_factory.getInputStream(socket);
                        Out=socket_factory.getOutputStream(socket);
                    }
                    //if(timeout>0){ socket.setSoTimeout(timeout); }
                    socket.setTcpNoDelay(true);
                    io.setInputStream(In);
                    io.setOutputStream(Out);
                }
                else
                {
                    lock(proxy)
                    {
                        proxy.connect(socket_factory, host, port, connectTimeout);
                        io.setInputStream(proxy.getInputStream());
                        io.setOutputStream(proxy.getOutputStream());
                        socket=proxy.getSocket();
                    }
                }

                if(connectTimeout>0 && socket!=null)
                {
                    socket.setSoTimeout(connectTimeout);
                }

                _isConnected=true;

                while(true)
                {

                    i=0;
                    j=0;
                    while(i<buf.buffer.Length)
                    {
                        j=io.getByte();
                        if(j<0)break;
                        buf.buffer[i]=(byte)j; i++;
                        if(j==10)break;
                    }
                    if(j<0)
                    {
                        throw new JSchException("connection is closed by foreign host");
                    }

                    if(buf.buffer[i-1]==10)
                    {    // 0x0a
                        i--;
                        if(buf.buffer[i-1]==13)
                        {  // 0x0d
                            i--;
                        }
                    }

                    if(i>4 && (i!=buf.buffer.Length) &&
                        (buf.buffer[0]!='S'||buf.buffer[1]!='S'||
                        buf.buffer[2]!='H'||buf.buffer[3]!='-'))
                    {
                        //System.err.println(new String(buf.buffer, 0, i);
                        continue;
                    }

                    if(i==buf.buffer.Length ||
                        i<7 ||                                      // SSH-1.99 or SSH-2.0
                        (buf.buffer[4]=='1' && buf.buffer[6]!='9')  // SSH-1.5
                        )
                    {
                        throw new JSchException("invalid server's version String");
                    }
                    break;
                }

                V_S=new byte[i]; SharpSSH.SharpSsh.java.System.arraycopy(buf.buffer, 0, V_S, 0, i);
                //System.Console.WriteLine("V_S: ("+i+") ["+new String(V_S)+"]");

                //io.put(V_C, 0, V_C.Length); io.put("\n".getBytes(), 0, 1);
            {
                // Some Cisco devices will miss to read '\n' if it is sent separately.
                byte[] foo=new byte[V_C.Length+1];
                SharpSSH.SharpSsh.java.System.arraycopy(V_C, 0, foo, 0, V_C.Length);
                foo[foo.Length-1]=(byte)'\n';
                io.put(foo, 0, foo.Length);
            }

                buf=read(buf);
                //System.Console.WriteLine("read: 20 ? "+buf.buffer[5]);
                if(buf.buffer[5]!=SSH_MSG_KEXINIT)
                {
                    throw new JSchException("invalid protocol: "+buf.buffer[5]);
                }
                KeyExchange kex=receive_kexinit(buf);

                while(true)
                {
                    buf=read(buf);
                    if(kex.getState()==buf.buffer[5])
                    {
                        bool result=kex.next(buf);
                        if(!result)
                        {
                            //System.Console.WriteLine("verify: "+result);
                            in_kex=false;
                            throw new JSchException("verify: "+result);
                        }
                    }
                    else
                    {
                        in_kex=false;
                        throw new JSchException("invalid protocol(kex): "+buf.buffer[5]);
                    }
                    if(kex.getState()==KeyExchange.STATE_END)
                    {
                        break;
                    }
                }

                try{ checkHost(host, kex); }
                catch(JSchException ee)
                {
                    in_kex=false;
                    throw ee;
                }

                send_newkeys();

                // receive SSH_MSG_NEWKEYS(21)
                buf=read(buf);
                //System.Console.WriteLine("read: 21 ? "+buf.buffer[5]);
                if(buf.buffer[5]==SSH_MSG_NEWKEYS)
                {
                    receive_newkeys(buf, kex);
                }
                else
                {
                    in_kex=false;
                    throw new JSchException("invalid protocol(newkyes): "+buf.buffer[5]);
                }

                bool auth=false;
                bool auth_cancel=false;

                UserAuthNone usn=new UserAuthNone(userinfo);
                auth=usn.start(this);

                String methods=null;
                if(!auth)
                {
                    methods=usn.getMethods();
                    if(methods!=null)
                    {
                        methods=methods.toLowerCase();
                    }
                    else
                    {
                        // methods: publickey,password,keyboard-interactive
                        methods="publickey,password,keyboard-interactive";
                    }
                }

            loop:
                while(true)
                {

                    //System.Console.WriteLine("methods: "+methods);

                    while(!auth &&
                        methods!=null && methods.Length()>0)
                    {

                        //System.Console.WriteLine("  methods: "+methods);

                        UserAuth us=null;
                        if(methods.startsWith("publickey"))
                        {
                            //System.Console.WriteLine("   jsch.identities.size()="+jsch.identities.size());
                            lock(jsch.identities)
                            {
                                if(jsch.identities.size()>0)
                                {
                                    us=new UserAuthPublicKey(userinfo);
                                }
                            }
                        }
                        else if(methods.startsWith("keyboard-interactive"))
                        {
                            if(userinfo is UIKeyboardInteractive)
                            {
                                us=new UserAuthKeyboardInteractive(userinfo);
                            }
                        }
                        else if(methods.startsWith("password"))
                        {
                            us=new UserAuthPassword(userinfo);
                        }
                        if(us!=null)
                        {
                            try
                            {
                                auth=us.start(this);
                                auth_cancel=false;
                            }
                            catch(JSchAuthCancelException ee)
                            {
                                //System.Console.WriteLine(ee);
                                auth_cancel=true;
                            }
                            catch(JSchPartialAuthException ee)
                            {
                                methods=ee.getMethods();
                                //System.Console.WriteLine("PartialAuth: "+methods);
                                auth_cancel=false;
                                continue;//loop;
                            }
                            catch(RuntimeException ee)
                            {
                                throw ee;
                            }
                            catch(Exception ee)
                            {
                                System.Console.WriteLine("ee: "+ee); // SSH_MSG_DISCONNECT: 2 Too many authentication failures
                            }
                        }
                        if(!auth)
                        {
                            int comma=methods.indexOf(",");
                            if(comma==-1) break;
                            methods=methods.subString(comma+1);
                        }
                    }
                    break;
                }

                if(connectTimeout>0 || timeout>0)
                {
                    socket.setSoTimeout(timeout);
                }

                if(auth)
                {
                    isAuthed=true;
                    connectThread=new Thread(this);
                    connectThread.setName("Connect thread "+host+" session");
                    connectThread.start();
                    return;
                }
                if(auth_cancel)
                    throw new JSchException("Auth cancel");
                throw new JSchException("Auth fail");
            }
            catch(Exception e)
            {
                in_kex=false;
                if(_isConnected)
                {
                    try
                    {
                        packet.reset();
                        buf.putByte((byte)SSH_MSG_DISCONNECT);
                        buf.putInt(3);
                        buf.putString(new String(e.ToString()).getBytes());
                        buf.putString(new String("en").getBytes());
                        write(packet);
                        disconnect();
                    }
                    catch(Exception ee)
                    {
                    }
                }
                _isConnected=false;
                //e.printStackTrace();
                if(e is RuntimeException) throw (RuntimeException)e;
                if(e is JSchException) throw (JSchException)e;
                throw new JSchException("Session.connect: "+e);
            }
        }