/*
* Created on Jul 29, 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;
import java.nio.ByteBuffer;
import org.gudy.azureus2.core3.config.*;
import org.gudy.azureus2.core3.download.DownloadManager;
import org.gudy.azureus2.core3.global.GlobalManagerListener;
import org.gudy.azureus2.core3.util.Debug;
import com.aelitis.azureus.core.AzureusCoreFactory;
import com.aelitis.azureus.core.networkmanager.impl.*;
import com.aelitis.azureus.core.networkmanager.impl.http.HTTPNetworkManager;
import com.aelitis.azureus.core.networkmanager.impl.tcp.TCPNetworkManager;
import com.aelitis.azureus.core.networkmanager.impl.udp.UDPNetworkManager;
import com.aelitis.azureus.core.peermanager.messaging.*;
/**
*
*/
public class NetworkManager {
public static final int UNLIMITED_RATE = 1024 * 1024 * 100; //100 mbyte/s
private static final NetworkManager instance = new NetworkManager();
private static int max_download_rate_bps;
private static int max_upload_rate_bps_normal;
private static int max_upload_rate_bps_seeding_only;
private static int max_upload_rate_bps;
private static boolean lan_rate_enabled;
private static int max_lan_upload_rate_bps;
private static int max_lan_download_rate_bps;
private static boolean seeding_only_mode_allowed;
private static boolean seeding_only_mode = false;
public static boolean REQUIRE_CRYPTO_HANDSHAKE;
public static boolean INCOMING_HANDSHAKE_FALLBACK_ALLOWED;
public static boolean OUTGOING_HANDSHAKE_FALLBACK_ALLOWED;
static {
COConfigurationManager.addAndFireParameterListeners(
new String[]{ "network.transport.encrypted.require",
"network.transport.encrypted.fallback.incoming",
"network.transport.encrypted.fallback.outgoing",
"LAN Speed Enabled",
"Max Upload Speed KBs",
"Max LAN Upload Speed KBs",
"Max Upload Speed Seeding KBs",
"enable.seedingonly.upload.rate",
"Max Download Speed KBs",
"Max LAN Download Speed KBs",
"network.tcp.mtu.size",
"network.udp.mtu.size" },
new ParameterListener() {
public void parameterChanged( String ignore ) {
REQUIRE_CRYPTO_HANDSHAKE = COConfigurationManager.getBooleanParameter( "network.transport.encrypted.require");
INCOMING_HANDSHAKE_FALLBACK_ALLOWED = COConfigurationManager.getBooleanParameter( "network.transport.encrypted.fallback.incoming");
OUTGOING_HANDSHAKE_FALLBACK_ALLOWED = COConfigurationManager.getBooleanParameter( "network.transport.encrypted.fallback.outgoing");
max_upload_rate_bps_normal = COConfigurationManager.getIntParameter( "Max Upload Speed KBs" ) * 1024;
if( max_upload_rate_bps_normal < 1024 ) max_upload_rate_bps_normal = UNLIMITED_RATE;
if( max_upload_rate_bps_normal > UNLIMITED_RATE ) max_upload_rate_bps_normal = UNLIMITED_RATE;
max_lan_upload_rate_bps = COConfigurationManager.getIntParameter( "Max LAN Upload Speed KBs" ) * 1024;
if( max_lan_upload_rate_bps < 1024 ) max_lan_upload_rate_bps = UNLIMITED_RATE;
if( max_lan_upload_rate_bps > UNLIMITED_RATE ) max_lan_upload_rate_bps = UNLIMITED_RATE;
max_upload_rate_bps_seeding_only = COConfigurationManager.getIntParameter( "Max Upload Speed Seeding KBs" ) * 1024;
if( max_upload_rate_bps_seeding_only < 1024 ) max_upload_rate_bps_seeding_only = UNLIMITED_RATE;
if( max_upload_rate_bps_seeding_only > UNLIMITED_RATE ) max_upload_rate_bps_seeding_only = UNLIMITED_RATE;
seeding_only_mode_allowed = COConfigurationManager.getBooleanParameter( "enable.seedingonly.upload.rate" );
max_download_rate_bps = COConfigurationManager.getIntParameter( "Max Download Speed KBs" ) * 1024;
if( max_download_rate_bps < 1024 ) max_download_rate_bps = UNLIMITED_RATE;
if( max_download_rate_bps > UNLIMITED_RATE ) max_download_rate_bps = UNLIMITED_RATE;
lan_rate_enabled = COConfigurationManager.getBooleanParameter("LAN Speed Enabled");
max_lan_download_rate_bps = COConfigurationManager.getIntParameter( "Max LAN Download Speed KBs" ) * 1024;
if( max_lan_download_rate_bps < 1024 ) max_lan_download_rate_bps = UNLIMITED_RATE;
if( max_lan_download_rate_bps > UNLIMITED_RATE ) max_lan_download_rate_bps = UNLIMITED_RATE;
refreshRates();
}
});
}
private final WriteController write_controller = new WriteController();
private final ReadController read_controller = new ReadController();
private final TransferProcessor upload_processor = new TransferProcessor( TransferProcessor.TYPE_UPLOAD, new LimitedRateGroup(){
public int getRateLimitBytesPerSecond() { return max_upload_rate_bps; }
});
private final TransferProcessor download_processor = new TransferProcessor( TransferProcessor.TYPE_DOWNLOAD, new LimitedRateGroup(){
public int getRateLimitBytesPerSecond() { return max_download_rate_bps; }
});
private final TransferProcessor lan_upload_processor = new TransferProcessor( TransferProcessor.TYPE_UPLOAD, new LimitedRateGroup(){
public int getRateLimitBytesPerSecond() { return max_lan_upload_rate_bps; }
});
private final TransferProcessor lan_download_processor = new TransferProcessor( TransferProcessor.TYPE_DOWNLOAD, new LimitedRateGroup(){
public int getRateLimitBytesPerSecond() { return max_lan_download_rate_bps; }
});
public static boolean
isLANRateEnabled()
{
return( lan_rate_enabled );
}
private NetworkManagerStats stats = new NetworkManagerStats();
private NetworkManager() {
}
public static int getMinMssSize() { return Math.min( TCPNetworkManager.getTcpMssSize(), UDPNetworkManager.getUdpMssSize()); }
private static void refreshRates() {
if( isSeedingOnlyUploadRate() ) {
max_upload_rate_bps = max_upload_rate_bps_seeding_only;
}
else {
max_upload_rate_bps = max_upload_rate_bps_normal;
}
if( max_upload_rate_bps < 1024 ) {
Debug.out( "max_upload_rate_bps < 1024=" +max_upload_rate_bps);
}
//ensure that mss isn't greater than up/down rate limits
int min_rate = Math.min( max_upload_rate_bps,
Math.min( max_download_rate_bps,
Math.min( max_lan_upload_rate_bps, max_lan_download_rate_bps )));
TCPNetworkManager.refreshRates( min_rate );
UDPNetworkManager.refreshRates( min_rate );
}
public static boolean isSeedingOnlyUploadRate() {
return seeding_only_mode_allowed && seeding_only_mode;
}
public static int getMaxUploadRateBPSNormal() {
if( max_upload_rate_bps_normal == UNLIMITED_RATE ) return 0;
return max_upload_rate_bps_normal;
}
public static int getMaxUploadRateBPSSeedingOnly() {
if( max_upload_rate_bps_seeding_only == UNLIMITED_RATE ) return 0;
return max_upload_rate_bps_seeding_only;
}
public static int getMaxDownloadRateBPS() {
if( max_download_rate_bps == UNLIMITED_RATE ) return 0;
return max_download_rate_bps;
}
public static final int CRYPTO_OVERRIDE_NONE = 0;
public static final int CRYPTO_OVERRIDE_REQUIRED = 1;
public static final int CRYPTO_OVERRIDE_NOT_REQUIRED = 2;
public static boolean
getCryptoRequired(
int override_level )
{
if ( override_level == CRYPTO_OVERRIDE_NONE ){
return( REQUIRE_CRYPTO_HANDSHAKE );
}else if ( override_level == CRYPTO_OVERRIDE_REQUIRED ){
return( true );
}else{
return( false );
}
}
public void initialize() {
HTTPNetworkManager.getSingleton();
AzureusCoreFactory.getSingleton().getGlobalManager().addListener( new GlobalManagerListener() {
public void downloadManagerAdded( DownloadManager dm ){}
public void downloadManagerRemoved( DownloadManager dm ){}
public void destroyInitiated(){}
public void destroyed(){}
public void seedingStatusChanged( boolean seeding_only ) {
seeding_only_mode = seeding_only;
refreshRates();
}
});
}
/**
* Get the singleton instance of the network manager.
* @return the network manager
*/
public static NetworkManager getSingleton() { return instance; }
/**
* Create a new unconnected remote network connection (for outbound-initiated connections).
* @param remote_address to connect to
* @param encoder default message stream encoder to use for the outgoing queue
* @param decoder default message stream decoder to use for the incoming queue
* @return a new connection
*/
public NetworkConnection createConnection( ConnectionEndpoint target, MessageStreamEncoder encoder, MessageStreamDecoder decoder, boolean connect_with_crypto, boolean allow_fallback, byte[][] shared_secrets ) {
return NetworkConnectionFactory.create( target, encoder, decoder, connect_with_crypto, allow_fallback, shared_secrets );
}
/**
* Request the acceptance and routing of new incoming connections that match the given initial byte sequence.
* @param matcher initial byte sequence used for routing
* @param listener for handling new inbound connections
* @param factory to use for creating default stream encoder/decoders
*/
public void
requestIncomingConnectionRouting(
ByteMatcher matcher,
final RoutingListener listener,
final MessageStreamFactory factory )
{
IncomingConnectionManager.getSingleton().registerMatchBytes( matcher, new IncomingConnectionManager.MatchListener() {
public boolean
autoCryptoFallback()
{
return( listener.autoCryptoFallback());
}
public void connectionMatched( Transport transport, Object routing_data ) {
listener.connectionRouted( NetworkConnectionFactory.create( transport, factory.createEncoder(), factory.createDecoder() ), routing_data );
}
});
}
public NetworkConnection
bindTransport(
Transport transport,
MessageStreamEncoder encoder,
MessageStreamDecoder decoder )
{
return( NetworkConnectionFactory.create( transport, encoder, decoder ));
}
/**
* Cancel a request for inbound connection routing.
* @param matcher byte sequence originally used to register
*/
public void cancelIncomingConnectionRouting( ByteMatcher matcher ) {
IncomingConnectionManager.getSingleton().deregisterMatchBytes( matcher );
}
/**
* Add an upload entity for write processing.
* @param entity to add
*/
public void addWriteEntity( RateControlledEntity entity ) {
write_controller.addWriteEntity( entity );
}
/**
* Remove an upload entity from write processing.
* @param entity to remove
*/
public void removeWriteEntity( RateControlledEntity entity ) {
write_controller.removeWriteEntity( entity );
}
/**
* Add a download entity for read processing.
* @param entity to add
*/
public void addReadEntity( RateControlledEntity entity ) {
read_controller.addReadEntity( entity );
}
/**
* Remove a download entity from read processing.
* @param entity to remove
*/
public void removeReadEntity( RateControlledEntity entity ) {
read_controller.removeReadEntity( entity );
}
/**
* Register peer connection for network upload and download handling.
* NOTE: The given max rate limits are ignored until the connection is upgraded.
* NOTE: The given max rate limits are ignored for LANLocal connections.
* @param peer_connection to register for network transfer processing
* @param upload_group upload rate limit group
* @param download_group download rate limit group
*/
public void
startTransferProcessing(
NetworkConnectionBase peer_connection )
{
if( peer_connection.isLANLocal() && lan_rate_enabled ) {
lan_upload_processor.registerPeerConnection( peer_connection, true );
lan_download_processor.registerPeerConnection( peer_connection, false );
}
else {
upload_processor.registerPeerConnection( peer_connection, true );
download_processor.registerPeerConnection( peer_connection, false );
}
}
/**
* Cancel network upload and download handling for the given connection.
* @param peer_connection to cancel
*/
public void stopTransferProcessing( NetworkConnectionBase peer_connection ) {
if( lan_upload_processor.isRegistered( peer_connection )) {
lan_upload_processor.deregisterPeerConnection( peer_connection );
lan_download_processor.deregisterPeerConnection( peer_connection );
}
else {
upload_processor.deregisterPeerConnection( peer_connection );
download_processor.deregisterPeerConnection( peer_connection );
}
}
/**
* Upgrade the given connection to high-speed network transfer handling.
* @param peer_connection to upgrade
*/
public void upgradeTransferProcessing( NetworkConnectionBase peer_connection ) {
if( lan_upload_processor.isRegistered( peer_connection )) {
lan_upload_processor.upgradePeerConnection( peer_connection );
lan_download_processor.upgradePeerConnection( peer_connection );
}
else {
upload_processor.upgradePeerConnection( peer_connection );
download_processor.upgradePeerConnection( peer_connection );
}
}
/**
* Downgrade the given connection back to a normal-speed network transfer handling.
* @param peer_connection to downgrade
*/
public void downgradeTransferProcessing( NetworkConnectionBase peer_connection ) {
if( lan_upload_processor.isRegistered( peer_connection )) {
lan_upload_processor.downgradePeerConnection( peer_connection );
lan_download_processor.downgradePeerConnection( peer_connection );
}
else {
upload_processor.downgradePeerConnection( peer_connection );
download_processor.downgradePeerConnection( peer_connection );
}
}
public void
addRateLimiter(
NetworkConnectionBase peer_connection,
LimitedRateGroup group,
boolean upload )
{
if ( upload ){
if ( lan_upload_processor.isRegistered( peer_connection )){
lan_upload_processor.addRateLimiter( peer_connection, group );
}else{
upload_processor.addRateLimiter( peer_connection, group );
}
}else{
if ( lan_download_processor.isRegistered( peer_connection )){
lan_download_processor.addRateLimiter( peer_connection, group );
}else{
download_processor.addRateLimiter( peer_connection, group );
}
}
}
public void
removeRateLimiter(
NetworkConnectionBase peer_connection,
LimitedRateGroup group,
boolean upload )
{
if ( upload ){
if ( lan_upload_processor.isRegistered( peer_connection )){
lan_upload_processor.removeRateLimiter( peer_connection, group );
}else{
upload_processor.removeRateLimiter( peer_connection, group );
}
}else{
if ( lan_download_processor.isRegistered( peer_connection )){
lan_download_processor.removeRateLimiter( peer_connection, group );
}else{
download_processor.removeRateLimiter( peer_connection, group );
}
}
}
public NetworkManagerStats
getStats()
{
return( stats );
}
/**
* Byte stream match filter for routing.
*/
public interface ByteMatcher {
/**
* Number of bytes of buffer at or beyond which the "match" method will be called to test for a match
* @return
*/
public int matchThisSizeOrBigger();
/**
* Get the max number of bytes this matcher requires. If it fails with this (or more) bytes then
* the connection will be dropped
* @return size in bytes
*/
public int maxSize();
/**
* Get the minimum number of bytes required to determine if this matcher applies
* @return
*/
public int minSize();
/**
* Check byte stream for match.
* @param address the originator of the connection
* @param to_compare
* @return return "routing data" in case of a match, null otherwise
*/
public Object matches( TransportHelper transport, ByteBuffer to_compare, int port );
/**
* Check for a minimum match
* @param to_compare
* @return return "routing data" in case of a match, null otherwise
*/
public Object minMatches( TransportHelper transport, ByteBuffer to_compare, int port );
public byte[][] getSharedSecrets();
public int getSpecificPort();
}
/**
* Listener for routing events.
*/
public interface RoutingListener {
/**
* Currently if message crypto is on and default fallback for incoming not
* enabled then we would bounce incoming messages from non-crypto transports
* For example, NAT check
* This method allows auto-fallback for such transports
* @return
*/
public boolean
autoCryptoFallback();
/**
* The given incoming connection has been accepted.
* @param connection accepted
*/
public void connectionRouted( NetworkConnection connection, Object routing_data );
}
}
|