Hi ymnk,
I never heard back from you on this issue.
The problem is that the main Session loop blocks when calling
channel.write() while handling incoming SSH_MSG_CHANNEL_DATA. When that
happens, all channels in the entire Session stop communicating. To
resolve this, I instead write the message data to a queue, and I create
a background thread to process the queue and write the actual data.
You may not agree with my implementation, but it works for me, and I
have tested it extensively.
Here is the patch diff to 0.1.45:
==== BEGIN PATCH =====
Index: src/main/java/com/jcraft/jsch/Channel.java
===================================================================
--- src/main/java/com/jcraft/jsch/Channel.java (revision 253)
+++ src/main/java/com/jcraft/jsch/Channel.java (working copy)
@@ -119,6 +119,8 @@
volatile int reply=0;
volatile int connectTimeout=0;
+ WriteQueue writeQueue = new WriteQueue();
+
private Session session;
int notifyme=0;
@@ -416,19 +418,19 @@
}
void write(byte[] foo, int s, int l) throws IOException {
try{
- io.put(foo, s, l);
+ writeQueue.add(new WriteMessage(foo,s,l,false));
}catch(NullPointerException e){}
}
void write_ext(byte[] foo, int s, int l) throws IOException {
try{
- io.put_ext(foo, s, l);
+ writeQueue.add(new WriteMessage(foo,s,l,true));
}catch(NullPointerException e){}
}
void eof_remote(){
eof_remote=true;
try{
- io.out_close();
+ writeQueue.add(new WriteMessage(null,0,0,false));
}
catch(NullPointerException e){}
}
@@ -557,7 +559,7 @@
try{
if(io!=null){
- io.close();
+ writeQueue.add(null);
}
}
catch(Exception e){
@@ -662,4 +664,106 @@
catch(Exception e){
}
}
+
+ class WriteQueue implements Runnable{
+ final java.util.LinkedList writeList = new java.util.LinkedList();
+ Thread writeThread = null;
+
+ private synchronized void add(WriteMessage writeMessage){
+ if (writeThread ==null){
+ writeThread=new Thread(this,"WriteQueue thread for Channel: "+id);
+ writeThread.start();
+ }
+
+ synchronized(writeList){
+ writeList.add(writeMessage);
+ if (writeList.size()==1){
+ writeList.notify();
+ }
+ }
+ }
+ public void run(){
+ WriteMessage writeMessage = null;
+
+ try{
+ while(writeThread!=null){
+ synchronized(writeList){
+ if (writeList.size()<=0){
+ if(close){
+ writeThread=null;
+ break;
+ }
+ try{writeList.wait(10000);} catch(InterruptedException ie){}
+ if(writeList.size()<=0){continue;}
+ }
+
+ writeMessage=(WriteMessage)writeList.removeFirst();
+ }
+
+ if (writeMessage==null){
+ writeThread=null;
+ break;
+ }
+
+ writeMessage.write();
+ }
+ }
+ catch(Throwable t){
+ writeThread=null;
+ }
+
+ if (io!=null){
+ io.close();
+ io=null;
+ }
+ }
+ }
+ class WriteMessage{
+ boolean extData = false;
+ byte[] msg = null;
+
+ public WriteMessage(byte[] foo, int s, int l, boolean ext){
+ extData = ext;
+ if (l>0){
+ msg=new byte[l];
+ System.arraycopy(foo, s, msg, 0, l);
+ }
+ }
+ void write() throws Exception{
+ if (msg==null){
+ try{
+ io.out_close();
+ }catch(Throwable e){}
+ return;
+ }
+ else if (extData){
+ try{
+ io.put_ext(msg, 0, msg.length);
+ }catch(Throwable e){
+ try{disconnect();}catch(Throwable ee){}
+ return;
+ }
+ }
+ else{
+ try{
+ io.put(msg, 0, msg.length);
+ }catch(Throwable e){
+ try{disconnect();}catch(Throwable ee){}
+ return;
+ }
+ }
+
+ setLocalWindowSize(lwsize-msg.length);
+ if(lwsize<lwsize_max/2){
+ Buffer buf=new Buffer(100);
+ Packet packet=new Packet(buf);
+ packet.reset();
+ buf.putByte((byte)Session.SSH_MSG_CHANNEL_WINDOW_ADJUST);
+ buf.putInt(getRecipient());
+ buf.putInt(lwsize_max-lwsize);
+ getSession().write(packet);
+ setLocalWindowSize(lwsize_max);
+ }
+ }
+ }
}
Index: src/main/java/com/jcraft/jsch/Session.java
===================================================================
--- src/main/java/com/jcraft/jsch/Session.java (revision 253)
+++ src/main/java/com/jcraft/jsch/Session.java (working copy)
@@ -1332,6 +1332,7 @@
try{channel.disconnect();}catch(Exception ee){}
break;
}
+/*
int len=length[0];
channel.setLocalWindowSize(channel.lwsize-len);
if(channel.lwsize<channel.lwsize_max/2){
@@ -1342,6 +1343,7 @@
write(packet);
channel.setLocalWindowSize(channel.lwsize_max);
}
+*/
break;
case SSH_MSG_CHANNEL_EXTENDED_DATA:
@@ -1362,6 +1364,7 @@
channel.write_ext(foo, start[0], length[0]);
+/*
len=length[0];
channel.setLocalWindowSize(channel.lwsize-len);
if(channel.lwsize<channel.lwsize_max/2){
@@ -1372,6 +1375,7 @@
write(packet);
channel.setLocalWindowSize(channel.lwsize_max);
}
+*/
break;
case SSH_MSG_CHANNEL_WINDOW_ADJUST:
==== END PATCH =====
On 10/21/2011 5:55 PM, B. Scott Smith wrote:
> Hi ymnk,
>
> I am experiencing an issue in which one slow client is effecting all
> client performance. To simplify and demonstrate the issue, I setup a
> test case in which I forward 2 ports: one to a web server and one to
> another service, say telnet. I then issue a "wget" command to request
> a large file from the web server. While the file is downloading, I
> suspend the wget process (control Z). At this point, no other client
> can connect to the web server, and also any active telnet clients stop
> working. When I resume the wget process, everything works again. I try
> this exact test with the native command-line ssh client, and it all
> works fine.
>
> I have tried this with version 0.1.44 as well as an older version
> (0.1.41).
>
> Any ideas?
> Thanks in advance.
> - Scott
------------------------------------------------------------------------------
Ridiculously easy VDI. With Citrix VDI-in-a-Box, you don't need a complex
infrastructure or vast IT resources to deliver seamless, secure access to
virtual desktops. With this all-in-one solution, easily deploy virtual
desktops for less than the cost of PCs and save 60% on VDI infrastructure
costs. Try it free! http://p.sf.net/sfu/Citrix-VDIinabox
_______________________________________________
JSch-users mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/jsch-users