Index: /home/maurer/stuff/workspace/james-dev/src/java/org/apache/james/core/AbstractJamesService.java
===================================================================
--- /home/maurer/stuff/workspace/james-dev/src/java/org/apache/james/core/AbstractJamesService.java	(revision 390042)
+++ /home/maurer/stuff/workspace/james-dev/src/java/org/apache/james/core/AbstractJamesService.java	(working copy)
@@ -126,6 +126,12 @@
      * The maximum number of connections allowed for this service.
      */
     protected Integer connectionLimit;
+    
+    /**
+     * The maximum number of connections per IP allowed for this service.
+     */
+    protected Integer connectionLimitPerIP;
+
 
     /**
      * The connection idle timeout.  Used primarily to prevent server
@@ -300,6 +306,7 @@
                 }
             } else {
                 connectionLimit = new Integer(((JamesConnectionManager)connectionManager).getMaximumNumberOfOpenConnections());
+                connectionLimitPerIP = new Integer(((JamesConnectionManager)connectionManager).getMaximumNumberOfOpenConnectionsPerIP());
             }
             infoBuffer = new StringBuffer(128)
                 .append(getServiceType())
@@ -350,10 +357,10 @@
         if ((connectionLimit != null) &&
             (connectionManager instanceof JamesConnectionManager)) {
             if (null != threadPool) {
-                ((JamesConnectionManager)connectionManager).connect(connectionName, serverSocket, this, threadPool, connectionLimit.intValue());
+                ((JamesConnectionManager)connectionManager).connect(connectionName, serverSocket, this, threadPool, connectionLimit.intValue(),connectionLimitPerIP.intValue());
             }
             else {
-                ((JamesConnectionManager)connectionManager).connect(connectionName, serverSocket, this, connectionLimit.intValue()); // default pool
+                ((JamesConnectionManager)connectionManager).connect(connectionName, serverSocket, this, connectionLimit.intValue(),connectionLimitPerIP.intValue()); // default pool
             }
         } else {
             if (null != threadPool) {
Index: /home/maurer/stuff/workspace/james-dev/src/java/org/apache/james/services/JamesConnectionManager.java
===================================================================
--- /home/maurer/stuff/workspace/james-dev/src/java/org/apache/james/services/JamesConnectionManager.java	(revision 384301)
+++ /home/maurer/stuff/workspace/james-dev/src/java/org/apache/james/services/JamesConnectionManager.java	(working copy)
@@ -42,6 +42,14 @@
      * @return the maximum number of connections
      */
     int getMaximumNumberOfOpenConnections();
+    
+    /**
+     * Returns the default maximum number of open connections per IP supported by this
+     * SimpleConnectionManager
+     *
+     * @return the maximum number of connections per IP
+     */
+    int getMaximumNumberOfOpenConnectionsPerIP();
 
     /**
      * Start managing a connection.
@@ -53,6 +61,7 @@
      * @param handlerFactory the factory from which to acquire handlers
      * @param threadPool the thread pool to use
      * @param maxOpenConnections the maximum number of open connections allowed for this server socket.
+     * @param maxOpenConnectionsPerIP the maximum number of open connections per IP allowed for this server socket.
      * @exception Exception if an error occurs
      */
     void connect( String name,
@@ -59,7 +68,8 @@
                   ServerSocket socket,
                   ConnectionHandlerFactory handlerFactory,
                   ThreadPool threadPool,
-                  int maxOpenConnections )
+                  int maxOpenConnections,
+                  int maxOpenConnectionsPerIP)
         throws Exception;
     
     /**
@@ -70,6 +80,7 @@
      * @param socket the ServerSocket from which to
      * @param handlerFactory the factory from which to acquire handlers
      * @param maxOpenConnections the maximum number of open connections allowed for this server socket.
+     * @param maxOpenConnectionsPerIP the maximum number of open connections per IP allowed for this server socket.
      * @exception Exception if an error occurs
      */
     void connect( String name,
@@ -75,7 +86,8 @@
     void connect( String name,
                   ServerSocket socket,
                   ConnectionHandlerFactory handlerFactory,
-                  int maxOpenConnections )
+                  int maxOpenConnections,
+                  int maxOpenConnectionsPerIP)
         throws Exception;
 
     /**
Index: /home/maurer/stuff/workspace/james-dev/src/java/org/apache/james/util/connection/ServerConnection.java
===================================================================
--- /home/maurer/stuff/workspace/james-dev/src/java/org/apache/james/util/connection/ServerConnection.java	(revision 384301)
+++ /home/maurer/stuff/workspace/james-dev/src/java/org/apache/james/util/connection/ServerConnection.java	(working copy)
@@ -23,6 +23,7 @@
 import java.net.Socket;
 import java.net.SocketException;
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.Iterator;
 
 import org.apache.avalon.cornerstone.services.connection.ConnectionHandler;
@@ -96,6 +97,12 @@
      * connection will allow.
      */
     private int maxOpenConn;
+    
+    /**
+     * The maximum number of open client connections per IP that this server
+     * connection will allow.
+     */
+    private int maxOpenConnPerIP;
 
     /**
      * A collection of client connection runners.
@@ -101,7 +108,12 @@
      * A collection of client connection runners.
      */
     private final ArrayList clientConnectionRunners = new ArrayList();
-
+    
+    /**
+     * A HashMap of clientip and connections
+     */
+    private final HashMap connectionPerIP = new HashMap();
+    
     /**
      * The thread used to manage this server connection.
      */
@@ -117,6 +129,8 @@
      * @param timeout the client idle timeout for this ServerConnection's client connections
      * @param maxOpenConn the maximum number of open client connections allowed for this
      *                    ServerConnection
+     * @param maxOpenConnPerIP the maximum number of open client connections allowed for this
+     *                    ServerConnection per IP
      */
     public ServerConnection(ServerSocket serverSocket,
                             ConnectionHandlerFactory handlerFactory,
@@ -122,7 +136,7 @@
                             ConnectionHandlerFactory handlerFactory,
                             ThreadPool threadPool,
                             int timeout,
-                            int maxOpenConn) {
+                            int maxOpenConn, int maxOpenConnPerIP) {
         this.serverSocket = serverSocket;
         this.handlerFactory = handlerFactory;
         connThreadPool = threadPool;
@@ -128,6 +142,7 @@
         connThreadPool = threadPool;
         socketTimeout = timeout;
         this.maxOpenConn = maxOpenConn;
+        this.maxOpenConnPerIP = maxOpenConnPerIP;
     }
 
     /**
@@ -159,7 +174,9 @@
                 serverConnectionThread = null;
                 thread.interrupt();
                 try {
+                    
                     serverSocket.close();
+                    
                 } catch (IOException ie) {
                     // Ignored - we're doing this to break out of the
                     // accept.  This minimizes the time required to
@@ -191,6 +208,8 @@
                 runner = null;
             }
             clientConnectionRunners.clear();
+            clearConnectionPerIP();
+            
         }
 
         getLogger().debug("Cleaned up clients - " + this.toString());
@@ -243,6 +262,57 @@
     }
 
     /**
+     * Raise the connectionCount for the given ipAdrress
+     * @param ip raise the connectionCount for the given ipAddress
+     */
+    private void addConnectionPerIP (String ip) {
+        connectionPerIP.put(ip,Integer.toString(getConnectionPerIP(ip) +1));
+    }
+    
+    /**
+     * Get the count of connections for the given ip
+     * @param ip the ipAddress to get the connections for. 
+     * @return count
+     */
+    private int getConnectionPerIP(String ip) {
+        int count = 0;
+        String curCount = null;
+        Object c = connectionPerIP.get(ip);
+        
+        if (c != null) {
+            curCount = c.toString();
+            
+            if (curCount != null) {
+                return Integer.parseInt(curCount);
+            }
+        }
+        return count;
+    }
+    
+    /**
+     * Set the connection count for the given ipAddress
+     * @param ip ipAddres for which we want to set the count
+     */
+    private void removeConnectionPerIP (String ip) {
+
+        int count = getConnectionPerIP(ip);
+        if (count > 1) {
+            connectionPerIP.put(ip,Integer.toString(count -1));
+        } else {
+            // not need this entry any more
+            connectionPerIP.remove(ip);
+        }
+
+    }
+    
+    /**
+     * Clear the connection count map
+     */
+    private void clearConnectionPerIP () {
+        connectionPerIP.clear();
+    }
+    
+    /**
      * Provides the body for the thread of execution for a ServerConnection.
      * Connections made to the server socket are passed to an appropriate,
      * newly created, ClientConnectionRunner
@@ -304,10 +374,26 @@
                             // We ignore this exception, as we already have an error condition.
                         }
                         continue;
+                    } else if ((maxOpenConnPerIP > 0) && (getConnectionPerIP(clientSocket.getInetAddress().getHostAddress()) >= maxOpenConnPerIP)) {
+                        getLogger().info("Maximum number of open connections per IP exceeded - refusing connection.  Current number of connections is " + getConnectionPerIP(clientSocket.getInetAddress().getHostAddress()));
+                            
+                        if (getLogger().isWarnEnabled()) {
+                                
+                            getLogger().warn("Maximum number of open connections per IP exceeded - refusing connection.  Current number of connections is " + getConnectionPerIP(clientSocket.getInetAddress().getHostAddress()));
+                        }
+                        try {
+                            clientSocket.close();
+                        } catch (IOException ignored) {
+                            // We ignore this exception, as we already have an error condition.
+                        }
+                        continue;
+                        
                     } else {
+                        addConnectionPerIP(clientSocket.getInetAddress().getHostAddress());
                         clientSocket.setSoTimeout(socketTimeout);
                         runner = addClientConnectionRunner();
                         runner.setSocket(clientSocket);
+                        
                     }
                 }
                 setupLogger( runner );
@@ -320,6 +406,7 @@
                     getLogger().error("Internal error - insufficient threads available to service request.  " +
                                       Thread.activeCount() + " threads in service request pool.", e);
                     try {
+                        removeConnectionPerIP(clientSocket.getInetAddress().getHostAddress());
                         clientSocket.close();
                     } catch (IOException ignored) {
                         // We ignore this exception, as we already have an error condition.
@@ -368,7 +455,7 @@
 
         public ClientConnectionRunner() {
         }
-
+        
         /**
          * The dispose operation that terminates the runner.  Should only be
          * called by the ServerConnection that owns the ClientConnectionRunner
@@ -430,6 +517,9 @@
                 getLogger().error( "Error handling connection", e );
             } finally {
 
+                // remove this connection from map!
+                removeConnectionPerIP(clientSocket.getInetAddress().getHostAddress());
+                
                 // Close the underlying socket
                 try {
                     if (clientSocket != null) {
Index: /home/maurer/stuff/workspace/james-dev/src/java/org/apache/james/util/connection/SimpleConnectionManager.java
===================================================================
--- /home/maurer/stuff/workspace/james-dev/src/java/org/apache/james/util/connection/SimpleConnectionManager.java	(revision 384301)
+++ /home/maurer/stuff/workspace/james-dev/src/java/org/apache/james/util/connection/SimpleConnectionManager.java	(working copy)
@@ -56,6 +56,12 @@
      */
     private static final int DEFAULT_MAX_CONNECTIONS = 30;
     /**
+     * The default value for the maximum number of allowed client
+     * connections.
+     */
+    private static final int DEFAULT_MAX_CONNECTIONS_PER_IP = 0;
+    
+    /**
      * The map of connection name / server connections managed by this connection
      * manager.
      */
@@ -69,6 +75,10 @@
      */
     protected int maxOpenConn = 0;
     /**
+     * The maximum number of client connections allowed per server connection per IP.
+     */
+    protected int maxOpenConnPerIP = 0;
+    /**
      * The ThreadManager component that is used to provide a default thread pool.
      */
     private ThreadManager threadManager;
@@ -82,6 +92,7 @@
     public void configure(final Configuration configuration) throws ConfigurationException {
         timeout = configuration.getChild("idle-timeout").getValueAsInteger(DEFAULT_SOCKET_TIMEOUT);
         maxOpenConn = configuration.getChild("max-connections").getValueAsInteger(DEFAULT_MAX_CONNECTIONS);
+        maxOpenConnPerIP = configuration.getChild("max-connections-per-ip").getValueAsInteger(DEFAULT_MAX_CONNECTIONS_PER_IP);
         if (timeout < 0) {
             StringBuffer exceptionBuffer =
                 new StringBuffer(128).append("Specified socket timeout value of ").append(timeout).append(
@@ -95,6 +106,13 @@
                     " is not a legal value.");
             throw new ConfigurationException(exceptionBuffer.toString());
         }
+        if (maxOpenConnPerIP < 0) {
+            StringBuffer exceptionBuffer =
+                new StringBuffer(128).append("Specified maximum number of open connections per IP of ").append(
+                    maxOpenConnPerIP).append(
+                    " is not a legal value.");
+            throw new ConfigurationException(exceptionBuffer.toString());
+        }
         if (getLogger().isDebugEnabled()) {
             getLogger().debug(
                 "Connection timeout is " + (timeout == 0 ? "unlimited" : Long.toString(timeout)));
@@ -149,7 +167,8 @@
         ServerSocket socket,
         ConnectionHandlerFactory handlerFactory,
         ThreadPool threadPool,
-        int maxOpenConnections)
+        int maxOpenConnections,
+        int maxOpenConnectionsPerIP)
         throws Exception {
         if (disposed) {
             throw new IllegalStateException("Connection manager has already been shutdown.");
@@ -159,9 +178,12 @@
         }
         if (maxOpenConnections < 0) {
             throw new IllegalArgumentException("The maximum number of client connections per server socket cannot be less that zero.");
+        } 
+        if (maxOpenConnectionsPerIP < 0) {
+            throw new IllegalArgumentException("The maximum number of client connections (per IP) per server socket cannot be less that zero.");
         }
         ServerConnection runner =
-            new ServerConnection(socket, handlerFactory, threadPool, timeout, maxOpenConnections);
+            new ServerConnection(socket, handlerFactory, threadPool, timeout, maxOpenConnections, maxOpenConnectionsPerIP);
         setupLogger(runner);
         ContainerUtil.initialize(runner);
         connectionMap.put(name, runner);
@@ -184,7 +206,7 @@
         ConnectionHandlerFactory handlerFactory,
         ThreadPool threadPool)
         throws Exception {
-        connect(name, socket, handlerFactory, threadPool, maxOpenConn);
+        connect(name, socket, handlerFactory, threadPool, maxOpenConn,maxOpenConnPerIP);
     }
     /**
      * Start managing a connection.
@@ -207,6 +229,7 @@
      * @param socket the ServerSocket from which to
      * @param handlerFactory the factory from which to acquire handlers
      * @param maxOpenConnections the maximum number of open connections allowed for this server socket.
+     * @param maxOpenConnections the maximum number of open connections per IP allowed for this server socket.
      * @exception Exception if an error occurs
      */
     public void connect(
@@ -213,9 +236,10 @@
         String name,
         ServerSocket socket,
         ConnectionHandlerFactory handlerFactory,
-        int maxOpenConnections)
+        int maxOpenConnections,
+        int maxOpenConnectionsPerIP)
         throws Exception {
-        connect(name, socket, handlerFactory, threadManager.getDefaultThreadPool(), maxOpenConnections);
+        connect(name, socket, handlerFactory, threadManager.getDefaultThreadPool(), maxOpenConnections, maxOpenConnectionsPerIP);
     }
     /**
      * This shuts down all handlers and socket, waiting for each to gracefully shutdown.
@@ -253,5 +277,16 @@
     public int getMaximumNumberOfOpenConnections() {
         return maxOpenConn;
     }
+    
+    /**
+     * Returns the default maximum number of open connections per IP supported by this
+     * SimpleConnectionManager
+     *
+     * @return the maximum number of connections
+     */
+    public int getMaximumNumberOfOpenConnectionsPerIP() {
+        return maxOpenConnPerIP;
+    }
 
+
 }
Index: /home/maurer/stuff/workspace/james-dev/src/conf/james-config.xml
===================================================================
--- /home/maurer/stuff/workspace/james-dev/src/conf/james-config.xml	(revision 394291)
+++ /home/maurer/stuff/workspace/james-dev/src/conf/james-config.xml	(working copy)
@@ -1154,9 +1154,17 @@
    <!-- Resource limitations imposed by other components (i.e. max # of threads) may -->
    <!-- serve to limit the number of open connections. -->
    <!-- -->
+   <!-- The max-connections-per-ip parameter specifies the default maximum number of client -->
+   <!-- connections per ip that this connection manager will allow per managed server socket. -->
+   <!-- This value can be overridden by each individual service. -->
+   <!-- If no value is specified, the value defaults to 0 ( disabled) . -->
+   <!-- -->
    <connections>
       <idle-timeout>300000</idle-timeout>
       <max-connections>30</max-connections>
+      <!--
+      <max-connections-per-ip>0</max-connections-per-ip>
+      -->
    </connections>
 
    <!-- The Socket Manager block -->
