org/sonews/daemon/Connections.java
author chris <chris@marvin>
Fri, 26 Jun 2009 16:48:50 +0200
changeset 1 6fceb66e1ad7
child 3 2fdc9cc89502
permissions -rw-r--r--
Hooray... sonews/0.5.0 final

HG: Enter commit message. Lines beginning with 'HG:' are removed.
HG: Remove all lines to abort the collapse operation.
     1 /*
     2  *   SONEWS News Server
     3  *   see AUTHORS for the list of contributors
     4  *
     5  *   This program is free software: you can redistribute it and/or modify
     6  *   it under the terms of the GNU General Public License as published by
     7  *   the Free Software Foundation, either version 3 of the License, or
     8  *   (at your option) any later version.
     9  *
    10  *   This program is distributed in the hope that it will be useful,
    11  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
    12  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    13  *   GNU General Public License for more details.
    14  *
    15  *   You should have received a copy of the GNU General Public License
    16  *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
    17  */
    18 
    19 package org.sonews.daemon;
    20 
    21 import org.sonews.util.Log;
    22 import java.io.IOException;
    23 import java.net.InetSocketAddress;
    24 import java.net.Socket;
    25 import java.nio.channels.SocketChannel;
    26 import java.util.ArrayList;
    27 import java.util.HashMap;
    28 import java.util.List;
    29 import java.util.ListIterator;
    30 import java.util.Map;
    31 import org.sonews.util.Stats;
    32 
    33 /**
    34  * Daemon thread collecting all NNTPConnection instances. The thread
    35  * checks periodically if there are stale/timed out connections and
    36  * removes and purges them properly.
    37  * @author Christian Lins
    38  * @since sonews/0.5.0
    39  */
    40 final class Connections extends AbstractDaemon
    41 {
    42 
    43   private static final Connections instance = new Connections();
    44   
    45   /**
    46    * @return Active Connections instance.
    47    */
    48   public static Connections getInstance()
    49   {
    50     return Connections.instance;
    51   }
    52   
    53   private final List<NNTPConnection> connections 
    54     = new ArrayList<NNTPConnection>();
    55   private final Map<SocketChannel, NNTPConnection> connByChannel 
    56     = new HashMap<SocketChannel, NNTPConnection>();
    57   
    58   private Connections()
    59   {
    60     setName("Connections");
    61   }
    62   
    63   /**
    64    * Adds the given NNTPConnection to the Connections management.
    65    * @param conn
    66    * @see org.sonews.daemon.NNTPConnection
    67    */
    68   public void add(final NNTPConnection conn)
    69   {
    70     synchronized(this.connections)
    71     {
    72       this.connections.add(conn);
    73       this.connByChannel.put(conn.getChannel(), conn);
    74     }
    75   }
    76   
    77   /**
    78    * @param channel
    79    * @return NNTPConnection instance that is associated with the given
    80    * SocketChannel.
    81    */
    82   public NNTPConnection get(final SocketChannel channel)
    83   {
    84     synchronized(this.connections)
    85     {
    86       return this.connByChannel.get(channel);
    87     }
    88   }
    89 
    90   int getConnectionCount(String remote)
    91   {
    92     int cnt = 0;
    93     synchronized(this.connections)
    94     {
    95       for(NNTPConnection conn : this.connections)
    96       {
    97         assert conn != null;
    98         assert conn.getChannel() != null;
    99 
   100         Socket socket = conn.getChannel().socket();
   101         if(socket != null)
   102         {
   103           InetSocketAddress sockAddr = (InetSocketAddress)socket.getRemoteSocketAddress();
   104           if(sockAddr != null)
   105           {
   106             if(sockAddr.getHostName().equals(remote))
   107             {
   108               cnt++;
   109             }
   110           }
   111         } // if(socket != null)
   112       }
   113     }
   114     return cnt;
   115   }
   116   
   117   /**
   118    * Run loops. Checks periodically for timed out connections and purged them
   119    * from the lists.
   120    */
   121   @Override
   122   public void run()
   123   {
   124     while(isRunning())
   125     {
   126       int timeoutMillis = 1000 * Config.getInstance().get(Config.TIMEOUT, 180);
   127       
   128       synchronized (this.connections)
   129       {
   130         final ListIterator<NNTPConnection> iter = this.connections.listIterator();
   131         NNTPConnection conn;
   132 
   133         while (iter.hasNext())
   134         {
   135           conn = iter.next();
   136           if((System.currentTimeMillis() - conn.getLastActivity()) > timeoutMillis)
   137           {
   138             // A connection timeout has occurred so purge the connection
   139             iter.remove();
   140 
   141             // Close and remove the channel
   142             SocketChannel channel = conn.getChannel();
   143             connByChannel.remove(channel);
   144             
   145             try
   146             {
   147               // Close the channel; implicitely cancels all selectionkeys
   148               channel.close();
   149               Log.msg("Disconnected: " + channel.socket().getRemoteSocketAddress() +
   150                 " (timeout)", true);
   151             }
   152             catch(IOException ex)
   153             {
   154               Log.msg("Connections.run(): " + ex, false);
   155             }
   156 
   157             // Recycle the used buffers
   158             conn.getBuffers().recycleBuffers();
   159             
   160             Stats.getInstance().clientDisconnect();
   161           }
   162         }
   163       }
   164 
   165       try
   166       {
   167         Thread.sleep(10000); // Sleep ten seconds
   168       }
   169       catch(InterruptedException ex)
   170       {
   171         Log.msg("Connections Thread was interrupted: " + ex.getMessage(), false);
   172       }
   173     }
   174   }
   175   
   176 }