1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/org/sonews/daemon/Connections.java Fri Jun 26 16:48:50 2009 +0200
1.3 @@ -0,0 +1,176 @@
1.4 +/*
1.5 + * SONEWS News Server
1.6 + * see AUTHORS for the list of contributors
1.7 + *
1.8 + * This program is free software: you can redistribute it and/or modify
1.9 + * it under the terms of the GNU General Public License as published by
1.10 + * the Free Software Foundation, either version 3 of the License, or
1.11 + * (at your option) any later version.
1.12 + *
1.13 + * This program is distributed in the hope that it will be useful,
1.14 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
1.15 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1.16 + * GNU General Public License for more details.
1.17 + *
1.18 + * You should have received a copy of the GNU General Public License
1.19 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
1.20 + */
1.21 +
1.22 +package org.sonews.daemon;
1.23 +
1.24 +import org.sonews.util.Log;
1.25 +import java.io.IOException;
1.26 +import java.net.InetSocketAddress;
1.27 +import java.net.Socket;
1.28 +import java.nio.channels.SocketChannel;
1.29 +import java.util.ArrayList;
1.30 +import java.util.HashMap;
1.31 +import java.util.List;
1.32 +import java.util.ListIterator;
1.33 +import java.util.Map;
1.34 +import org.sonews.util.Stats;
1.35 +
1.36 +/**
1.37 + * Daemon thread collecting all NNTPConnection instances. The thread
1.38 + * checks periodically if there are stale/timed out connections and
1.39 + * removes and purges them properly.
1.40 + * @author Christian Lins
1.41 + * @since sonews/0.5.0
1.42 + */
1.43 +final class Connections extends AbstractDaemon
1.44 +{
1.45 +
1.46 + private static final Connections instance = new Connections();
1.47 +
1.48 + /**
1.49 + * @return Active Connections instance.
1.50 + */
1.51 + public static Connections getInstance()
1.52 + {
1.53 + return Connections.instance;
1.54 + }
1.55 +
1.56 + private final List<NNTPConnection> connections
1.57 + = new ArrayList<NNTPConnection>();
1.58 + private final Map<SocketChannel, NNTPConnection> connByChannel
1.59 + = new HashMap<SocketChannel, NNTPConnection>();
1.60 +
1.61 + private Connections()
1.62 + {
1.63 + setName("Connections");
1.64 + }
1.65 +
1.66 + /**
1.67 + * Adds the given NNTPConnection to the Connections management.
1.68 + * @param conn
1.69 + * @see org.sonews.daemon.NNTPConnection
1.70 + */
1.71 + public void add(final NNTPConnection conn)
1.72 + {
1.73 + synchronized(this.connections)
1.74 + {
1.75 + this.connections.add(conn);
1.76 + this.connByChannel.put(conn.getChannel(), conn);
1.77 + }
1.78 + }
1.79 +
1.80 + /**
1.81 + * @param channel
1.82 + * @return NNTPConnection instance that is associated with the given
1.83 + * SocketChannel.
1.84 + */
1.85 + public NNTPConnection get(final SocketChannel channel)
1.86 + {
1.87 + synchronized(this.connections)
1.88 + {
1.89 + return this.connByChannel.get(channel);
1.90 + }
1.91 + }
1.92 +
1.93 + int getConnectionCount(String remote)
1.94 + {
1.95 + int cnt = 0;
1.96 + synchronized(this.connections)
1.97 + {
1.98 + for(NNTPConnection conn : this.connections)
1.99 + {
1.100 + assert conn != null;
1.101 + assert conn.getChannel() != null;
1.102 +
1.103 + Socket socket = conn.getChannel().socket();
1.104 + if(socket != null)
1.105 + {
1.106 + InetSocketAddress sockAddr = (InetSocketAddress)socket.getRemoteSocketAddress();
1.107 + if(sockAddr != null)
1.108 + {
1.109 + if(sockAddr.getHostName().equals(remote))
1.110 + {
1.111 + cnt++;
1.112 + }
1.113 + }
1.114 + } // if(socket != null)
1.115 + }
1.116 + }
1.117 + return cnt;
1.118 + }
1.119 +
1.120 + /**
1.121 + * Run loops. Checks periodically for timed out connections and purged them
1.122 + * from the lists.
1.123 + */
1.124 + @Override
1.125 + public void run()
1.126 + {
1.127 + while(isRunning())
1.128 + {
1.129 + int timeoutMillis = 1000 * Config.getInstance().get(Config.TIMEOUT, 180);
1.130 +
1.131 + synchronized (this.connections)
1.132 + {
1.133 + final ListIterator<NNTPConnection> iter = this.connections.listIterator();
1.134 + NNTPConnection conn;
1.135 +
1.136 + while (iter.hasNext())
1.137 + {
1.138 + conn = iter.next();
1.139 + if((System.currentTimeMillis() - conn.getLastActivity()) > timeoutMillis)
1.140 + {
1.141 + // A connection timeout has occurred so purge the connection
1.142 + iter.remove();
1.143 +
1.144 + // Close and remove the channel
1.145 + SocketChannel channel = conn.getChannel();
1.146 + connByChannel.remove(channel);
1.147 +
1.148 + try
1.149 + {
1.150 + // Close the channel; implicitely cancels all selectionkeys
1.151 + channel.close();
1.152 + Log.msg("Disconnected: " + channel.socket().getRemoteSocketAddress() +
1.153 + " (timeout)", true);
1.154 + }
1.155 + catch(IOException ex)
1.156 + {
1.157 + Log.msg("Connections.run(): " + ex, false);
1.158 + }
1.159 +
1.160 + // Recycle the used buffers
1.161 + conn.getBuffers().recycleBuffers();
1.162 +
1.163 + Stats.getInstance().clientDisconnect();
1.164 + }
1.165 + }
1.166 + }
1.167 +
1.168 + try
1.169 + {
1.170 + Thread.sleep(10000); // Sleep ten seconds
1.171 + }
1.172 + catch(InterruptedException ex)
1.173 + {
1.174 + Log.msg("Connections Thread was interrupted: " + ex.getMessage(), false);
1.175 + }
1.176 + }
1.177 + }
1.178 +
1.179 +}