--- src/com/jcraft/jsch/Session.java.orig	Tue Mar 10 11:30:17 2009
+++ src/com/jcraft/jsch/Session.java	Thu Mar 26 17:52:01 2009
@@ -31,10 +31,23 @@
 
 import java.io.*;
 import java.net.*;
+import java.util.Iterator;
+import java.util.Set;
 
+import edu.emory.mathcs.backport.java.util.concurrent.ArrayBlockingQueue;
+import edu.emory.mathcs.backport.java.util.concurrent.ConcurrentMap;
+import edu.emory.mathcs.backport.java.util.concurrent.ConcurrentHashMap;
+
+
 public class Session implements Runnable{
-  static private final String version="JSCH-0.1.41";
+  static public final int UNAUTH_NO_LIMIT = Integer.MIN_VALUE;
 
+  static private boolean UNAUTH_LIMIT_ENABLED = false;
+  static private int UNAUTH_LIMIT_SIZE = UNAUTH_NO_LIMIT;
+  static private ConcurrentMap UNAUTH_LIMIT_MAP = new ConcurrentHashMap();
+  
+  static private final String version="JSCH-0.1.41.1";
+
   // http://ietf.org/internet-drafts/draft-ietf-secsh-assignednumbers-01.txt
   static final int SSH_MSG_DISCONNECT=                      1;
   static final int SSH_MSG_IGNORE=                          2;
@@ -146,11 +159,18 @@
     packet=new Packet(buf);
   }
 
+  public static synchronized boolean getUnauthenticatedLimitEnabled(){
+    return UNAUTH_LIMIT_ENABLED;
+  }  
+
   public void connect() throws JSchException{
     connect(timeout);
   }
 
   public void connect(int connectTimeout) throws JSchException{
+    boolean connectionAttempted = false;          
+    ArrayBlockingQueue unauthBlockingQueue = null;
+    
     if(isConnected){
       throw new JSchException("session is already connected");
     }
@@ -167,14 +187,35 @@
     }
     Packet.setRandom(random);
 
-    if(JSch.getLogger().isEnabled(Logger.INFO)){
-      JSch.getLogger().log(Logger.INFO, 
-                           "Connecting to "+host+" port "+port);
-    }
-
+   
     try	{
       int i, j;
 
+      
+      synchronized (UNAUTH_LIMIT_MAP) {
+		if (UNAUTH_LIMIT_ENABLED) {
+			int hostLimit = UNAUTH_LIMIT_SIZE;
+
+			connectionAttempted = true;
+
+			ArrayBlockingQueue tempBlockingQueue = new ArrayBlockingQueue(hostLimit);
+			unauthBlockingQueue = (ArrayBlockingQueue) UNAUTH_LIMIT_MAP.putIfAbsent(host, tempBlockingQueue);
+
+			if (unauthBlockingQueue == null) {
+				unauthBlockingQueue = tempBlockingQueue;
+			}
+
+			// this is a blocking call
+			unauthBlockingQueue.put(host);
+
+		}
+	}
+      
+	if(JSch.getLogger().isEnabled(Logger.INFO)){
+        JSch.getLogger().log(Logger.INFO, 
+                             "Connecting to "+host+" port "+port);
+      }
+
       if(proxy==null){
         InputStream in;
         OutputStream out;
@@ -495,6 +536,9 @@
       throw new JSchException("Session.connect: "+e);
     }
     finally{
+      if (connectionAttempted){
+        unauthBlockingQueue.poll();
+      }
       Util.bzero(this.password);
       this.password=null;
     }
@@ -1895,4 +1939,66 @@
       return false;
     }
   }
+  
+  /**
+   * Sets the default connection limits for unauthenticated connections.  The limit is per hostname (i.e. limit of 10 allows 10 unauthenticated connections to www.google.com and 10 unauthenticated connections to www.openssh.org)
+   * <p>
+   * If the limit is being changed to a different number (i.e. was previous set to 10 and now is being set to 5), this method will block until all pre-existing connections are authenticated (or closed).
+   * <p>
+   * To disable the limit, pass in UNAUTH_NO_LIMIT.
+   * 
+   * @param limit number of unauthenticated connections to allow per hostname.
+   * @throws JSchException if limit is not UNAUTH_NO_LIMIT and not >= 1
+   */
+  public static synchronized void setUnauthenticatedLimit(int limit) throws JSchException{
+	  if (limit == UNAUTH_LIMIT_SIZE){
+		  // no action needed.
+		  return;
+	  }
+	  
+	  if (limit < 1 && limit != UNAUTH_NO_LIMIT){
+		  throw new JSchException("Invalid unauthenticated connection limit: " + limit + ".  The limit must be >= 1 (or UNAUTH_NO_LIMIT)");
+	  }
+	  
+	  synchronized(UNAUTH_LIMIT_MAP){
+		  waitForAllUnauthenticatedConnections();
+		  UNAUTH_LIMIT_MAP.clear();
+		  
+		  if (limit == UNAUTH_NO_LIMIT){
+			  UNAUTH_LIMIT_ENABLED = false;
+		  }else{
+			  UNAUTH_LIMIT_ENABLED = true;
+		  }
+
+		  UNAUTH_LIMIT_SIZE = limit;
+	  }
+  }
+  
+  /** 
+   * Will block until all unauthenticated connections that are being tracked are completed (i.e. authenticated, closed, results in exception, etc...)
+   * <p>
+   * This method is <b>not</b> thread safe.  It is caller's responsibility to ensure thread safeness.
+   */
+  protected static void waitForAllUnauthenticatedConnections(){
+	  Set keys = UNAUTH_LIMIT_MAP.keySet();
+	  
+	  Iterator i = keys.iterator();
+	  
+	  while (i.hasNext()){
+		String key = (String)i.next();
+
+		ArrayBlockingQueue queue = (ArrayBlockingQueue)UNAUTH_LIMIT_MAP.get(key);
+		  
+		while (queue.size() != 0){
+		
+			try {
+				Thread.sleep(500);
+			} catch (InterruptedException e) {
+				// do nothing
+			}
+			  
+		}
+	  
+	  }	  
+  }
 }
