⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 connectionmanager.java

📁 java telnet 服务器实现 .
💻 JAVA
字号:
//License/*** * Java TelnetD library (embeddable telnet daemon) * Copyright (c) 2000-2005 Dieter Wimberger  * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * Neither the name of the author nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. *   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS ``AS * IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE  * POSSIBILITY OF SUCH DAMAGE. ***/
package net.wimpi.telnetd.net;

import net.wimpi.telnetd.BootException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import java.io.IOException;
import java.net.Socket;
import java.net.InetAddress;
import java.text.MessageFormat;
import java.util.*;

/**
 * Class that takes care for active and queued connection.
 * Housekeeping is done also for connections that were just broken
 * off, or exceeded their timeout. Note that instances of this class can
 * only be created by using the factory method createConnectionManager(Properties settings).
 *
 * @author Dieter Wimberger
 * @version 2.0 (16/07/2006)
 */
public class ConnectionManager
    implements Runnable {

  private static Log log = LogFactory.getLog(ConnectionManager.class);

  private Thread m_Thread;
  private ThreadGroup m_ThreadGroup;	//ThreadGroup all connections run in
  private List m_OpenConnections;
  private Stack m_ClosedConnections;
  private ConnectionFilter m_Filter; //reference to the connection filter
  private int m_MaxConnections;			//maximum allowed connections stored from the properties
  private int m_WarningTimeout;		//time to idle warning
  private int m_DisconnectTimeout;		//time to idle diconnection
  private int m_HousekeepingInterval;	//interval for managing cleanups
  private String m_LoginShell;
  private boolean m_LineMode = false;
  private boolean m_Stopping = false;


  private ConnectionManager(int con, int timew, int timedis,
                            int hoke, ConnectionFilter filter,
                            String lsh, boolean lm) {
    m_ThreadGroup = new ThreadGroup(new StringBuffer().append(this.toString()).append("Connections").toString());
    m_OpenConnections = Collections.synchronizedList(new ArrayList(100));
    //m_BrokenConnections = new Stack();
    m_ClosedConnections = new Stack();
    m_Filter = filter;
    m_LoginShell = lsh;
    m_LineMode = lm;
    m_MaxConnections = con;
    m_WarningTimeout = timew;
    m_DisconnectTimeout = timedis;
    m_HousekeepingInterval = hoke;
  }//constructor

  /**
   * Set a connection filter for this
   * ConnectionManager instance. The filter is used to handle
   * IP level allow/deny of incoming connections.
   *
   * @param filter ConnectionFilter instance.
   */
  public void setConnectionFilter(ConnectionFilter filter) {
    m_Filter = filter;
  }//setConnectionFilter

  /**
   * Gets the active ConnectionFilter instance or
   * returns null if no filter is set.
   *
   * @return the managers ConnectionFilter.
   */
  public ConnectionFilter getConnectionFilter() {
    return m_Filter;
  }//getConnectionFilter

  /**
   * Returns the number of open connections.
   * @return the number of open connections as <tt>int</tt>.
   */
  public int openConnectionCount() {
    return m_OpenConnections.size();
  }//openConnectionCount

  /**
   * Returns the {@link Connection} at the given index.
   * @param idx
   * @return
   */
  public Connection getConnection(int idx) {
    synchronized(m_OpenConnections) {
      return (Connection) m_OpenConnections.get(idx);
    }
  }//getConnection

  /**
   * Get all {@link Connection} instances with the given
   * <tt>InetAddress</tt>.
   *
   * @return all {@link Connection} instances with the given
   *         <tt>InetAddress</tt>.
   */
  public Connection[] getConnectionsByAdddress(InetAddress addr) {
    ArrayList l = new ArrayList();
    synchronized(m_OpenConnections) {
      for (Iterator iterator = m_OpenConnections.iterator(); iterator.hasNext();) {
        Connection connection = (Connection) iterator.next();
        if(connection.getConnectionData().getInetAddress().equals(addr)) {
          l.add(connection);
        }
      }
    }
    Connection[] conns = new Connection[l.size()];
    return (Connection[])l.toArray(conns);
  }//getConnectionsByAddress

  /**
   * Starts this <tt>ConnectionManager</tt>.
   */
  public void start() {
    m_Thread = new Thread(this);
    m_Thread.start();
  }//start

  /**
   * Stops this <tt>ConnectionManager</tt>.
   */
  public void stop() {
    log.debug("stop()::" +  this.toString());
    m_Stopping = true;
    //wait for thread to die
    try {
      m_Thread.join();
    } catch (InterruptedException iex) {
      log.error("stop()", iex);
    }
    synchronized(m_OpenConnections) {
      for (Iterator iter = m_OpenConnections.iterator(); iter.hasNext();) {
        try {
          Connection tc = (Connection) iter.next();
          //maybe write a disgrace to the socket?
          tc.close();
        } catch (Exception exc) {
          log.error("stop()", exc);
        }
      }
      m_OpenConnections.clear();
    }
    log.debug("stop():: Stopped " + this.toString());
  }//stop

  /**
   * Method that that tries to connect an incoming request.
   * Properly  queueing.
   *
   * @param insock Socket thats representing the incoming connection.
   */
  public void makeConnection(Socket insock) {
    log.debug("makeConnection()::" + insock.toString());
    if (m_Filter == null ||
        (m_Filter != null && m_Filter.isAllowed(insock.getInetAddress()))) {
      //we create the connection data object at this point to
      //store certain information there.
      ConnectionData newCD = new ConnectionData(insock, this);
      newCD.setLoginShell(m_LoginShell);
      newCD.setLineMode(m_LineMode);
      if (m_OpenConnections.size() < m_MaxConnections) {
        //create a new Connection instance
        Connection con = new Connection(m_ThreadGroup, newCD);
        //log the newly created connection
        Object[] args = {new Integer(m_OpenConnections.size() + 1)};
        log.info(MessageFormat.format("connection #{0,number,integer} made.", args));
        //register it for being managed
        synchronized(m_OpenConnections) {
          m_OpenConnections.add(con);
        }
        //start it
        con.start();
      }
    } else {
      log.info("makeConnection():: Active Filter blocked incoming connection.");
      try {
        insock.close();
      } catch (IOException ex) {
        //do nothing or log.
      }
    }
  }//makeConnection


  /**
   * Periodically does following work:
   * <ul>
   * <li> cleaning up died connections.
   * <li> checking managed connections if they are working properly.
   * <li> checking the open connections.
   * </ul>
   */
  public void run() {
    //housekeep connections
    try {
      do {
        //clean up and close all broken connections
        //cleanupBroken();
        //clean up closed connections
        cleanupClosed();
        //check all active connections
        checkOpenConnections();
        //sleep interval
        Thread.sleep(m_HousekeepingInterval);
      } while (!m_Stopping);

    } catch (Exception e) {
      log.error("run()", e);
    }
    log.debug("run():: Ran out " + this.toString());
  }//run

  /*
  private void cleanupBroken() {
    //cleanup loop
    while (!m_BrokenConnections.isEmpty()) {
      Connection nextOne = (Connection) m_BrokenConnections.pop();
      log.info("cleanupBroken():: Closing broken connection " + nextOne.toString());
      //fire logoff event for shell site cleanup , beware could hog the daemon thread
      nextOne.processConnectionEvent(new ConnectionEvent(nextOne, ConnectionEvent.CONNECTION_BROKEN));
      //close the connection, will be automatically registered as closed
      nextOne.close();
    }
  }//cleanupBroken
*/
  private void cleanupClosed() {
    if(m_Stopping) {
      return;
    }
    //cleanup loop
    while (!m_ClosedConnections.isEmpty()) {
      Connection nextOne = (Connection) m_ClosedConnections.pop();
      log.info("cleanupClosed():: Removing closed connection " + nextOne.toString());
      synchronized(m_OpenConnections) {
        m_OpenConnections.remove(nextOne);
      }
    }
  }//cleanupBroken

  private void checkOpenConnections() {
    if(m_Stopping) {
      return;
    }
    //do routine checks on active connections
    synchronized(m_OpenConnections) {
      for (Iterator iter = m_OpenConnections.iterator(); iter.hasNext();) {
        Connection conn = (Connection) iter.next();
        ConnectionData cd = conn.getConnectionData();
        //check if it is dead and remove it.
        if (!conn.isActive()) {
          registerClosedConnection(conn);
          continue;
        }
        /* Timeouts check */
        //first we caculate the inactivity time
        long inactivity = System.currentTimeMillis() - cd.getLastActivity();
        //now we check for warning and disconnection
        if (inactivity > m_WarningTimeout) {
          //..and for disconnect
          if (inactivity > (m_DisconnectTimeout + m_WarningTimeout)) {
            //this connection needs to be disconnected :)
            log.debug("checkOpenConnections():" + conn.toString() + " exceeded total timeout.");
            //fire logoff event for shell site cleanup , beware could hog the daemon thread
            conn.processConnectionEvent(new ConnectionEvent(conn, ConnectionEvent.CONNECTION_TIMEDOUT));
            //conn.close();
          } else {
            //this connection needs to be warned :)
            if (!cd.isWarned()) {
              log.debug("checkOpenConnections():" + conn.toString() + " exceeded warning timeout.");
              cd.setWarned(true);
              //warning event is fired but beware this could hog the daemon thread!!
              conn.processConnectionEvent(new ConnectionEvent(conn, ConnectionEvent.CONNECTION_IDLE));
            }
          }
        }
      }
      /* end Timeouts check */
    }
  }//checkConnections

  /**
   * Called by connections that got broken (i.e. I/O errors).
   * The housekeeper will properly close the connection,
   * and take care for misc necessary cleanup.
   *
   * @param con the connection that is broken.
   *
  public void registerBrokenConnection(Connection con) {
    if (!m_BrokenConnections.contains(con) && !m_ClosedConnections.contains(con)) {
      log.debug("registerBrokenConnection()::" + con.toString());
      m_BrokenConnections.push(con);
    }
  }//registerBrokenConnection
*/
  public void registerClosedConnection(Connection con) {
    if(m_Stopping) {
      return;
    }
    if (!m_ClosedConnections.contains(con)) {
      log.debug("registerClosedConnection()::" + con.toString());
      m_ClosedConnections.push(con);
    }
  }//unregister

  /**
   * Factory method for the ConnectionManager.<br>
   * A class operation that will return a new ConnectionManager instance.
   *
   * @param settings Properties containing the settings for this instance.
   */
  public static ConnectionManager createConnectionManager(String name, Properties settings)
      throws BootException {

    try {
      int maxc = Integer.parseInt(settings.getProperty(name + ".maxcon"));
      int timow = Integer.parseInt(settings.getProperty(name + ".time_to_warning"));
      int timodis = Integer.parseInt(settings.getProperty(name + ".time_to_timedout"));
      int hoke = Integer.parseInt(settings.getProperty(name + ".housekeepinginterval"));
      String filterclass = settings.getProperty(name + ".connectionfilter");
      ConnectionFilter filter = null;
      String loginshell = "";
      boolean linemode = false;
      if (filterclass != null && filterclass.length() != 0 && !filterclass.toLowerCase().equals("none")) {
        //load filter
        filter = (ConnectionFilter) Class.forName(filterclass).newInstance();
        filter.initialize(settings);
      }
      loginshell = settings.getProperty(name + ".loginshell");
      if (loginshell == null || loginshell.length() == 0) {
        log.error("Login shell not specified.");
        throw new BootException("Login shell must be specified.");
      }
      String inputmode = settings.getProperty(name + ".inputmode");
      if (inputmode == null || inputmode.length() == 0) {
        log.info("Input mode not specified using character input as default.");
        linemode = false;
      } else if (inputmode.toLowerCase().equals("line")) {
        linemode = true;
      }
      //return fabricated manager
      ConnectionManager cm = new ConnectionManager(maxc, timow, timodis, hoke, filter, loginshell, linemode);
      //set higher priority!
      //cm.setPriority(Thread.NORM_PRIORITY + 2);
      return cm;
    } catch (Exception ex) {
      log.error("createConnectionManager():", ex);
      throw new BootException("Failure while creating ConnectionManger instance:\n" + ex.getMessage());
    }
  }//createManager


}//class ConnectionManager

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -