/* * Created on Dec 4, 2004 * Created by Alon Rohter * Copyright (C) 2004, 2005, 2006 Aelitis, All Rights Reserved. * * 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 2 * 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, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * AELITIS, SAS au capital de 46,603.30 euros * 8 Allee Lenotre, La Grille Royale, 78600 Le Mesnil le Roi, France. * */ package com.aelitis.azureus.core.networkmanager.impl.tcp; import java.net.*; import java.nio.channels.*; import java.util.*; import org.gudy.azureus2.core3.logging.*; import org.gudy.azureus2.core3.util.*; import com.aelitis.azureus.core.networkmanager.VirtualServerChannelSelector; /** * Virtual server socket channel for listening and accepting incoming connections. */ public class VirtualNonBlockingServerChannelSelector implements VirtualServerChannelSelector { private static final LogIDs LOGID = LogIDs.NWMAN; private List server_channels = new ArrayList(); private final InetAddress bind_address; private int start_port; private int num_ports; private final int receive_buffer_size; private final VirtualBlockingServerChannelSelector.SelectListener listener; protected AEMonitor this_mon = new AEMonitor( "VirtualNonBlockingServerChannelSelector" ); private long last_accept_time; /** * Create a new server listening on the given address and reporting to the given listener. * @param bind_address ip+port to listen on * @param so_rcvbuf_size new socket receive buffer size * @param listener to notify of incoming connections */ public VirtualNonBlockingServerChannelSelector( InetSocketAddress bind_address, int so_rcvbuf_size, VirtualBlockingServerChannelSelector.SelectListener listener ) { this( bind_address.getAddress(), bind_address.getPort(), 1, so_rcvbuf_size, listener ); } public VirtualNonBlockingServerChannelSelector( InetAddress _bind_address, int _start_port, int _num_ports, int _so_rcvbuf_size, VirtualBlockingServerChannelSelector.SelectListener _listener ) { bind_address = _bind_address; start_port = _start_port; num_ports = _num_ports; receive_buffer_size = _so_rcvbuf_size; listener = _listener; } /** * Start the server and begin accepting incoming connections. * */ public void start() { try{ this_mon.enter(); if( !isRunning() ) { for (int i=start_port;i<start_port+num_ports;i++){ try { final ServerSocketChannel server_channel = ServerSocketChannel.open(); server_channels.add( server_channel ); server_channel.socket().setReuseAddress( true ); if( receive_buffer_size > 0 ) server_channel.socket().setReceiveBufferSize( receive_buffer_size ); server_channel.socket().bind( new InetSocketAddress( bind_address, i ), 1024 ); if (Logger.isEnabled()) Logger.log(new LogEvent(LOGID, "TCP incoming server socket " + bind_address)); server_channel.configureBlocking( false ); VirtualAcceptSelector.getSingleton().register( server_channel, new VirtualAcceptSelector.AcceptListener() { public void newConnectionAccepted( SocketChannel channel ) { last_accept_time = SystemTime.getCurrentTime(); listener.newConnectionAccepted( server_channel, channel ); } }); }catch( Throwable t ) { Debug.out( t ); Logger.log(new LogAlert(LogAlert.UNREPEATABLE, "ERROR, unable to bind TCP incoming server socket to " +i, t)); } } last_accept_time = SystemTime.getCurrentTime(); //init to now } }finally{ this_mon.exit(); } } /** * Stop the server. */ public void stop() { try{ this_mon.enter(); for (int i=0;i<server_channels.size();i++){ try { ServerSocketChannel server_channel = (ServerSocketChannel)server_channels.get(i); VirtualAcceptSelector.getSingleton().cancel( server_channel ); server_channel.close(); } catch( Throwable t ) { Debug.out( t ); } } server_channels.clear(); }finally{ this_mon.exit(); } } /** * Is this selector actively running * @return true if enabled, false if not running */ public boolean isRunning() { if ( server_channels.size() == 0 ){ return( false); } ServerSocketChannel server_channel = (ServerSocketChannel)server_channels.get(0); if( server_channel != null && server_channel.isOpen() ) return true; return false; } public InetAddress getBoundToAddress() { if ( server_channels.size() == 0 ){ return( null); } ServerSocketChannel server_channel = (ServerSocketChannel)server_channels.get(0); return server_channel.socket().getInetAddress(); } public long getTimeOfLastAccept() { return last_accept_time; } }