diff -r f907866f0e4b -r 6fceb66e1ad7 org/sonews/daemon/Connections.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/org/sonews/daemon/Connections.java Fri Jun 26 16:48:50 2009 +0200
@@ -0,0 +1,176 @@
+/*
+ * SONEWS News Server
+ * see AUTHORS for the list of contributors
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package org.sonews.daemon;
+
+import org.sonews.util.Log;
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.net.Socket;
+import java.nio.channels.SocketChannel;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.Map;
+import org.sonews.util.Stats;
+
+/**
+ * Daemon thread collecting all NNTPConnection instances. The thread
+ * checks periodically if there are stale/timed out connections and
+ * removes and purges them properly.
+ * @author Christian Lins
+ * @since sonews/0.5.0
+ */
+final class Connections extends AbstractDaemon
+{
+
+ private static final Connections instance = new Connections();
+
+ /**
+ * @return Active Connections instance.
+ */
+ public static Connections getInstance()
+ {
+ return Connections.instance;
+ }
+
+ private final List connections
+ = new ArrayList();
+ private final Map connByChannel
+ = new HashMap();
+
+ private Connections()
+ {
+ setName("Connections");
+ }
+
+ /**
+ * Adds the given NNTPConnection to the Connections management.
+ * @param conn
+ * @see org.sonews.daemon.NNTPConnection
+ */
+ public void add(final NNTPConnection conn)
+ {
+ synchronized(this.connections)
+ {
+ this.connections.add(conn);
+ this.connByChannel.put(conn.getChannel(), conn);
+ }
+ }
+
+ /**
+ * @param channel
+ * @return NNTPConnection instance that is associated with the given
+ * SocketChannel.
+ */
+ public NNTPConnection get(final SocketChannel channel)
+ {
+ synchronized(this.connections)
+ {
+ return this.connByChannel.get(channel);
+ }
+ }
+
+ int getConnectionCount(String remote)
+ {
+ int cnt = 0;
+ synchronized(this.connections)
+ {
+ for(NNTPConnection conn : this.connections)
+ {
+ assert conn != null;
+ assert conn.getChannel() != null;
+
+ Socket socket = conn.getChannel().socket();
+ if(socket != null)
+ {
+ InetSocketAddress sockAddr = (InetSocketAddress)socket.getRemoteSocketAddress();
+ if(sockAddr != null)
+ {
+ if(sockAddr.getHostName().equals(remote))
+ {
+ cnt++;
+ }
+ }
+ } // if(socket != null)
+ }
+ }
+ return cnt;
+ }
+
+ /**
+ * Run loops. Checks periodically for timed out connections and purged them
+ * from the lists.
+ */
+ @Override
+ public void run()
+ {
+ while(isRunning())
+ {
+ int timeoutMillis = 1000 * Config.getInstance().get(Config.TIMEOUT, 180);
+
+ synchronized (this.connections)
+ {
+ final ListIterator iter = this.connections.listIterator();
+ NNTPConnection conn;
+
+ while (iter.hasNext())
+ {
+ conn = iter.next();
+ if((System.currentTimeMillis() - conn.getLastActivity()) > timeoutMillis)
+ {
+ // A connection timeout has occurred so purge the connection
+ iter.remove();
+
+ // Close and remove the channel
+ SocketChannel channel = conn.getChannel();
+ connByChannel.remove(channel);
+
+ try
+ {
+ // Close the channel; implicitely cancels all selectionkeys
+ channel.close();
+ Log.msg("Disconnected: " + channel.socket().getRemoteSocketAddress() +
+ " (timeout)", true);
+ }
+ catch(IOException ex)
+ {
+ Log.msg("Connections.run(): " + ex, false);
+ }
+
+ // Recycle the used buffers
+ conn.getBuffers().recycleBuffers();
+
+ Stats.getInstance().clientDisconnect();
+ }
+ }
+ }
+
+ try
+ {
+ Thread.sleep(10000); // Sleep ten seconds
+ }
+ catch(InterruptedException ex)
+ {
+ Log.msg("Connections Thread was interrupted: " + ex.getMessage(), false);
+ }
+ }
+ }
+
+}