You are viewing a plain text version of this content. The canonical link for it is here.
Posted to server-dev@james.apache.org by no...@apache.org on 2006/05/10 05:21:50 UTC
svn commit: r405611 - in /james/server/trunk/src: conf/james-config.xml
java/org/apache/james/util/connection/ServerConnection.java
java/org/apache/james/util/connection/SimpleConnectionManager.java
Author: norman
Date: Tue May 9 20:21:46 2006
New Revision: 405611
URL: http://svn.apache.org/viewcvs?rev=405611&view=rev
Log:
new feature max-connection-per-ip. see JAMES-484
Modified:
james/server/trunk/src/conf/james-config.xml
james/server/trunk/src/java/org/apache/james/util/connection/ServerConnection.java
james/server/trunk/src/java/org/apache/james/util/connection/SimpleConnectionManager.java
Modified: james/server/trunk/src/conf/james-config.xml
URL: http://svn.apache.org/viewcvs/james/server/trunk/src/conf/james-config.xml?rev=405611&r1=405610&r2=405611&view=diff
==============================================================================
--- james/server/trunk/src/conf/james-config.xml (original)
+++ james/server/trunk/src/conf/james-config.xml Tue May 9 20:21:46 2006
@@ -1178,9 +1178,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 -->
Modified: james/server/trunk/src/java/org/apache/james/util/connection/ServerConnection.java
URL: http://svn.apache.org/viewcvs/james/server/trunk/src/java/org/apache/james/util/connection/ServerConnection.java?rev=405611&r1=405610&r2=405611&view=diff
==============================================================================
--- james/server/trunk/src/java/org/apache/james/util/connection/ServerConnection.java (original)
+++ james/server/trunk/src/java/org/apache/james/util/connection/ServerConnection.java Tue May 9 20:21:46 2006
@@ -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,12 +97,23 @@
* 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.
*/
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,17 +129,20 @@
* @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,
ThreadPool threadPool,
int timeout,
- int maxOpenConn) {
+ int maxOpenConn, int maxOpenConnPerIP) {
this.serverSocket = serverSocket;
this.handlerFactory = handlerFactory;
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 synchronized 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 synchronized 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 synchronized 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 synchronized 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) {
Modified: james/server/trunk/src/java/org/apache/james/util/connection/SimpleConnectionManager.java
URL: http://svn.apache.org/viewcvs/james/server/trunk/src/java/org/apache/james/util/connection/SimpleConnectionManager.java?rev=405611&r1=405610&r2=405611&view=diff
==============================================================================
--- james/server/trunk/src/java/org/apache/james/util/connection/SimpleConnectionManager.java (original)
+++ james/server/trunk/src/java/org/apache/james/util/connection/SimpleConnectionManager.java Tue May 9 20:21:46 2006
@@ -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)));
@@ -159,9 +177,12 @@
}
if (maxOpenConnections < 0) {
throw new IllegalArgumentException("The maximum number of client connections per server socket cannot be less that zero.");
+ }
+ if (maxOpenConnPerIP < 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, maxOpenConnPerIP);
setupLogger(runner);
ContainerUtil.initialize(runner);
connectionMap.put(name, runner);
@@ -207,6 +228,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(
@@ -253,5 +275,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;
+ }
+
}
---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org