org/sonews/daemon/Connections.java
author cli
Thu, 06 Aug 2009 18:41:34 +0200
changeset 6 dcc7e491fbc9
parent 3 2fdc9cc89502
child 15 f2293e8566f5
permissions -rw-r--r--
Removing doc subdir which resides now in sonews-doc repository.
     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.config.Config;
    22 import org.sonews.util.Log;
    23 import java.io.IOException;
    24 import java.net.InetSocketAddress;
    25 import java.net.Socket;
    26 import java.nio.channels.SocketChannel;
    27 import java.util.ArrayList;
    28 import java.util.HashMap;
    29 import java.util.List;
    30 import java.util.ListIterator;
    31 import java.util.Map;
    32 import org.sonews.util.Stats;
    33 
    34 /**
    35  * Daemon thread collecting all NNTPConnection instances. The thread
    36  * checks periodically if there are stale/timed out connections and
    37  * removes and purges them properly.
    38  * @author Christian Lins
    39  * @since sonews/0.5.0
    40  */
    41 public final class Connections extends AbstractDaemon
    42 {
    43 
    44   private static final Connections instance = new Connections();
    45   
    46   /**
    47    * @return Active Connections instance.
    48    */
    49   public static Connections getInstance()
    50   {
    51     return Connections.instance;
    52   }
    53   
    54   private final List<NNTPConnection> connections 
    55     = new ArrayList<NNTPConnection>();
    56   private final Map<SocketChannel, NNTPConnection> connByChannel 
    57     = new HashMap<SocketChannel, NNTPConnection>();
    58   
    59   private Connections()
    60   {
    61     setName("Connections");
    62   }
    63   
    64   /**
    65    * Adds the given NNTPConnection to the Connections management.
    66    * @param conn
    67    * @see org.sonews.daemon.NNTPConnection
    68    */
    69   public void add(final NNTPConnection conn)
    70   {
    71     synchronized(this.connections)
    72     {
    73       this.connections.add(conn);
    74       this.connByChannel.put(conn.getSocketChannel(), conn);
    75     }
    76   }
    77   
    78   /**
    79    * @param channel
    80    * @return NNTPConnection instance that is associated with the given
    81    * SocketChannel.
    82    */
    83   public NNTPConnection get(final SocketChannel channel)
    84   {
    85     synchronized(this.connections)
    86     {
    87       return this.connByChannel.get(channel);
    88     }
    89   }
    90 
    91   int getConnectionCount(String remote)
    92   {
    93     int cnt = 0;
    94     synchronized(this.connections)
    95     {
    96       for(NNTPConnection conn : this.connections)
    97       {
    98         assert conn != null;
    99         assert conn.getSocketChannel() != null;
   100 
   101         Socket socket = conn.getSocketChannel().socket();
   102         if(socket != null)
   103         {
   104           InetSocketAddress sockAddr = (InetSocketAddress)socket.getRemoteSocketAddress();
   105           if(sockAddr != null)
   106           {
   107             if(sockAddr.getHostName().equals(remote))
   108             {
   109               cnt++;
   110             }
   111           }
   112         } // if(socket != null)
   113       }
   114     }
   115     return cnt;
   116   }
   117   
   118   /**
   119    * Run loops. Checks periodically for timed out connections and purged them
   120    * from the lists.
   121    */
   122   @Override
   123   public void run()
   124   {
   125     while(isRunning())
   126     {
   127       int timeoutMillis = 1000 * Config.inst().get(Config.TIMEOUT, 180);
   128       
   129       synchronized (this.connections)
   130       {
   131         final ListIterator<NNTPConnection> iter = this.connections.listIterator();
   132         NNTPConnection conn;
   133 
   134         while (iter.hasNext())
   135         {
   136           conn = iter.next();
   137           if((System.currentTimeMillis() - conn.getLastActivity()) > timeoutMillis)
   138           {
   139             // A connection timeout has occurred so purge the connection
   140             iter.remove();
   141 
   142             // Close and remove the channel
   143             SocketChannel channel = conn.getSocketChannel();
   144             connByChannel.remove(channel);
   145             
   146             try
   147             {
   148               // Close the channel; implicitely cancels all selectionkeys
   149               channel.close();
   150               Log.msg("Disconnected: " + channel.socket().getRemoteSocketAddress() +
   151                 " (timeout)", true);
   152             }
   153             catch(IOException ex)
   154             {
   155               Log.msg("Connections.run(): " + ex, false);
   156             }
   157 
   158             // Recycle the used buffers
   159             conn.getBuffers().recycleBuffers();
   160             
   161             Stats.getInstance().clientDisconnect();
   162           }
   163         }
   164       }
   165 
   166       try
   167       {
   168         Thread.sleep(10000); // Sleep ten seconds
   169       }
   170       catch(InterruptedException ex)
   171       {
   172         Log.msg("Connections Thread was interrupted: " + ex.getMessage(), false);
   173       }
   174     }
   175   }
   176   
   177 }