Package com.aelitis.azureus.plugins.net.netstatus

Source Code of com.aelitis.azureus.plugins.net.netstatus.NetStatusProtocolTester

/*
* Created on Feb 15, 2008
* Created by Paul Gardner
*
* Copyright 2008 Vuze, Inc.  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; version 2 of the License only.
*
* 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.
*/


package com.aelitis.azureus.plugins.net.netstatus;

import java.net.InetSocketAddress;
import java.util.*;


import org.gudy.azureus2.core3.util.AERunnable;
import org.gudy.azureus2.core3.util.AESemaphore;
import org.gudy.azureus2.core3.util.AEThread2;
import org.gudy.azureus2.core3.util.BDecoder;
import org.gudy.azureus2.core3.util.BEncoder;
import org.gudy.azureus2.core3.util.Constants;
import org.gudy.azureus2.core3.util.DelayedEvent;
import org.gudy.azureus2.core3.util.HashWrapper;
import org.gudy.azureus2.core3.util.SimpleTimer;
import org.gudy.azureus2.core3.util.SystemTime;
import org.gudy.azureus2.core3.util.TimerEvent;
import org.gudy.azureus2.core3.util.TimerEventPerformer;
import org.gudy.azureus2.core3.util.TimerEventPeriodic;
import org.gudy.azureus2.plugins.PluginInterface;
import org.gudy.azureus2.plugins.ddb.DistributedDatabase;
import org.gudy.azureus2.plugins.ddb.DistributedDatabaseContact;
import org.gudy.azureus2.plugins.ddb.DistributedDatabaseException;
import org.gudy.azureus2.plugins.ddb.DistributedDatabaseKey;
import org.gudy.azureus2.plugins.ddb.DistributedDatabaseProgressListener;
import org.gudy.azureus2.plugins.ddb.DistributedDatabaseTransferHandler;
import org.gudy.azureus2.plugins.ddb.DistributedDatabaseTransferType;
import org.gudy.azureus2.plugins.ddb.DistributedDatabaseValue;

import com.aelitis.azureus.core.dht.DHT;
import com.aelitis.azureus.core.dht.transport.DHTTransportContact;
import com.aelitis.azureus.core.networkmanager.NetworkManager;
import com.aelitis.azureus.core.networkmanager.impl.tcp.TCPNetworkManager;
import com.aelitis.azureus.plugins.dht.DHTPlugin;
import com.aelitis.azureus.plugins.net.netstatus.NetStatusProtocolTesterBT.Session;


public class
NetStatusProtocolTester
  implements DistributedDatabaseTransferHandler
{
  private static final int REQUEST_HISTORY_MAX  = 64;
 
  private static final int MAX_ACTIVE_TESTS  = 3;
  private static final int MAX_TEST_TIME    = 120*1000;
 
  private static final int TEST_TYPE_BT    = 1;
 
  private static final int  VERSION_INITIAL  = 1;
 
  private static final int  CURRENT_VERSION  = VERSION_INITIAL;
   
  private static final int  BT_MAX_SLAVES  = 8;
 
  private NetStatusPlugin    plugin;
  private PluginInterface    plugin_interface;

  private DistributedDatabase  ddb;
   
  private DHTPlugin      dht_plugin;
 
 

  private testXferType transfer_type = new testXferType();

  private Map  request_history = 
    new LinkedHashMap(REQUEST_HISTORY_MAX,0.75f,true)
    {
      protected boolean
      removeEldestEntry(
           Map.Entry eldest)
      {
        return size() > REQUEST_HISTORY_MAX;
      }
    };
   
  private List active_tests     = new ArrayList();
 
  private TimerEventPeriodic  timer_event  = null;
   
  protected
  NetStatusProtocolTester(
    NetStatusPlugin    _plugin,
    PluginInterface    _plugin_interface )
  {
    plugin        = _plugin;
    plugin_interface  = _plugin_interface;
   
    try{
      PluginInterface dht_pi = plugin_interface.getPluginManager().getPluginInterfaceByClass( DHTPlugin.class );
     
      if ( dht_pi != null ){
       
        dht_plugin = (DHTPlugin)dht_pi.getPlugin();
      }

      ddb = plugin_interface.getDistributedDatabase();
     
      ddb.addTransferHandler( transfer_type, this );
     
      log( "DDB transfer type registered" );
     
    }catch( Throwable e ){
     
      log( "DDB transfer type registration failed", e );
    }
  }
 
  public NetStatusProtocolTesterBT
  runTest(
    final NetStatusProtocolTesterListener    listener )
  {
    return( runTest( "", listener ));
  }
 
  public NetStatusProtocolTesterBT
  runTest(
    String                    test_address,
    final NetStatusProtocolTesterListener    listener )
  {
    final NetStatusProtocolTesterBT bt_tester = new NetStatusProtocolTesterBT( this, true );

    bt_tester.addListener( listener );
   
    bt_tester.start();
   
    addToActive( bt_tester );
   
    try{
      if ( test_address.length() == 0 ){
       
        DHT[]  dhts = dht_plugin.getDHTs();
       
        DHT  target_dht = null;
       
        int  target_network  = Constants.isCVSVersion()?DHT.NW_CVS:DHT.NW_MAIN;
       
        for (int i=0;i<dhts.length;i++){
         
          if ( dhts[i].getTransport().getNetwork() == target_network ){
           
            target_dht = dhts[i];
           
            break;
          }
        }
       
        if ( target_dht == null ){
         
          listener.logError( "Distributed database unavailable" );
         
        }else{
         
          DHTTransportContact[] contacts = target_dht.getTransport().getReachableContacts();
         
          final List f_contacts = new ArrayList(Arrays.asList(contacts));
         
          final int[]  ok = new int[]{ 0 };
         
          final int  num_threads = Math.min( BT_MAX_SLAVES, contacts.length );
         
          listener.log( "Searching " + contacts.length + " contacts for " + num_threads + " test targets" );
             
          final AESemaphore  sem = new AESemaphore( "NetStatusProbe" );
         
          for (int i=0;i<num_threads;i++){
           
            new AEThread2( "NetStatusProbe", true )
            {
              public void
              run()
              {
                try{
                  while( !bt_tester.isDestroyed()){
                   
                    DHTTransportContact  contact = null;
                   
                    synchronized( ok ){
                     
                      if ( ok[0] < num_threads && f_contacts.size() > 0 ){
                       
                        contact = (DHTTransportContact)f_contacts.remove(0);
                      }
                    }
                   
                    if ( contact == null ){
                     
                      break;
                    }
                   
                    try{
                      DistributedDatabaseContact ddb_contact = ddb.importContact( contact.getAddress());
                     
                      if ( tryTest( bt_tester, ddb_contact )){
                       
                        synchronized( ok ){
                         
                          ok[0]++;
                        }
                      }
                    }catch( Throwable e ){
                     
                      listener.logError( "Contact import for " + contact.getName() + " failed", e );
                    }
                  }
                }finally{
                 
                  sem.release();
                }
              }
            }.start();
          }
         
          for (int i=0;i<num_threads;i++){
           
            sem.reserve();
          }
         
          listener.log( "Searching complete, " + ok[0] + " targets found" );
        }
      }else{
       
        String[]  bits = test_address.split( ":" );
       
        if ( bits.length != 2 ){
         
          log( "Invalid address - use <host>:<port> " );
         
          return( bt_tester );
        }
       
        InetSocketAddress address = new InetSocketAddress( bits[0].trim(), Integer.parseInt( bits[1].trim()));
        
        DistributedDatabaseContact contact = ddb.importContact( address );

        tryTest( bt_tester, contact );
      }
    }catch( Throwable e ){
     
      listener.logError( "Test failed", e );
     
    }finally{
     
      bt_tester.addListener(
        new NetStatusProtocolTesterListener()
        {
          public void
          sessionAdded(
            Session session)
          {
          }
         
          public void
          complete(
            NetStatusProtocolTesterBT tester )
          {
            removeFromActive( tester );
          }
         
          public void
          log(
            String    str )
          {
          }
         
          public void
          logError(
            String    str )
          {
          }
         
          public void
          logError(
            String    str,
            Throwable  e )
          {
          }
        });
     
      bt_tester.setOutboundConnectionsComplete();
     
      new DelayedEvent(
        "NetStatus:killer",
        10*1000,
        new AERunnable()
        {
          public void
          runSupport()
          {
            listener.log( "Destroying tester" );
           
            bt_tester.destroy();
          }
        });
    }
   
    return( bt_tester );
  }
 
  protected boolean
  tryTest(
    NetStatusProtocolTesterBT    bt_tester,
    DistributedDatabaseContact    contact )
  {
    boolean  use_crypto = NetworkManager.getCryptoRequired( NetworkManager.CRYPTO_OVERRIDE_NONE );

    log( "Trying test to " + contact.getName());
   
    Map  request = new HashMap();
   
    request.put( "v", new Long( CURRENT_VERSION ));
       
    request.put( "t", new Long( TEST_TYPE_BT ));
     
    request.put( "h", bt_tester.getServerHash());
     
    request.put( "c", new Long( use_crypto?1:0 ));
   
    Map  reply = sendRequest( contact, request );
       
    byte[]  server_hash = reply==null?null:(byte[])reply.get( "h" );
     
    if ( server_hash != null ){
       
      log( "    " + contact.getName() + " accepted test" );
     
      bt_tester.testOutbound( adjustLoopback( contact.getAddress()), server_hash, use_crypto );
     
      return( true );
     
    }else{
     
      log( "    " + contact.getName() + " declined test" );

      return( false );
    }
  }
 
  protected InetSocketAddress
  adjustLoopback(
    InetSocketAddress  address )
  {
    InetSocketAddress local = dht_plugin.getLocalAddress().getAddress();
   
    if ( local.getAddress().getHostAddress().equals( address.getAddress().getHostAddress())){
     
      return( new InetSocketAddress( "127.0.0.1", address.getPort()));
     
    }else{
     
      return( address );
    }
  }
 
  protected Map
  sendRequest(
    DistributedDatabaseContact  contact,
    Map              request )
  {
    try{
      log( "Sending DDB request to " + contact.getName() + " - " + request );
     
      DistributedDatabaseKey key = ddb.createKey( BEncoder.encode( request ));
     
      DistributedDatabaseValue value =
        contact.read(
          new DistributedDatabaseProgressListener()
          {
            public void
            reportSize(
              long  size )
            { 
            }
           
            public void
            reportActivity(
              String  str )
            { 
            }
           
            public void
            reportCompleteness(
              int    percent )
            {
            }
          },
          transfer_type,
          key,
          10000 );
     
      if ( value == null ){
       
        return( null );
      }
     
      Map reply = BDecoder.decode((byte[])value.getValue( byte[].class ));
     
      log( "    received reply - " + reply );
     
      return( reply );
     
    }catch( Throwable e ){
     
      log( "sendRequest failed", e );
     
      return( null );
    }
  }
 
  protected Map
  receiveRequest(
    InetSocketAddress  originator,
    Map          request )
  {
    Map  reply = new HashMap();
   
    Long  test_type  = (Long)request.get( "t" );
   
    reply.put( "v", new Long( CURRENT_VERSION ));
   
    if ( test_type != null ){
     
      if ( test_type.intValue() == TEST_TYPE_BT ){
       
        TCPNetworkManager tcp_man = TCPNetworkManager.getSingleton();
       
        InetSocketAddress adjusted_originator = adjustLoopback( originator );
       
        boolean  test = adjusted_originator.getAddress().isLoopbackAddress();
       
        if (   test ||
            tcp_man.isTCPListenerEnabled() &&
              tcp_man.getTCPListeningPortNumber() == ddb.getLocalContact().getAddress().getPort() &&
              SystemTime.getCurrentTime() - tcp_man.getLastIncomingNonLocalConnectionTime() <= 24*60*60*1000 )){
         
          byte[]  their_hash  = (byte[])request.get( "h" );
         
          if ( their_hash != null ){
           
            NetStatusProtocolTesterBT bt_tester;
           
            synchronized( active_tests ){
             
              if ( active_tests.size() > MAX_ACTIVE_TESTS ){
               
                log( "Too many active tests" );
               
                return( reply );
               
              }else{
               
                bt_tester = new NetStatusProtocolTesterBT( this, false );
               
                bt_tester.start();
               
                addToActive( bt_tester );
              }
            }
           
            Long  l_crypto = (Long)request.get( "c" );
           
            boolean  use_crypto = l_crypto!=null&&l_crypto.longValue()==1;
           
            bt_tester.testOutbound( adjusted_originator, their_hash, use_crypto );
           
            reply.put( "h", bt_tester.getServerHash());
          }
        }
      }
    }   
   
    return( reply );
  }
 
  protected void
  addToActive(
    NetStatusProtocolTesterBT    tester )
  {
    synchronized( active_tests ){

      active_tests.add( tester );
     
      if ( timer_event == null ){
       
        timer_event =
          SimpleTimer.addPeriodicEvent(
            "NetStatusProtocolTester:timer",
            30*1000,
            new TimerEventPerformer()
            {
              public void
              perform(
                TimerEvent event )
              {
                long  now = SystemTime.getCurrentTime();
               
                List  to_remove = new ArrayList();
               
                synchronized( active_tests ){

                  for (int i=0;i<active_tests.size();i++){
                   
                    NetStatusProtocolTesterBT tester = (NetStatusProtocolTesterBT)active_tests.get(i);
                   
                    long start = tester.getStartTime( now );
                   
                    if ( now - start > MAX_TEST_TIME ){
                     
                      to_remove.add( tester );
                    }
                  }
                }
               
                for ( int i=0;i<to_remove.size();i++ ){
                 
                  removeFromActive( (NetStatusProtocolTesterBT)to_remove.get(i));
                }
              }
            });
      }
    }
  }
 
  protected void
  removeFromActive(
    NetStatusProtocolTesterBT    tester )
  {
    tester.destroy();
   
    synchronized( active_tests ){
     
      active_tests.remove( tester );
     
      if ( active_tests.size() == 0 ){
       
        if ( timer_event != null ){
         
          timer_event.cancel();
         
          timer_event = null;
        }
      }
    }
  }
 
  public DistributedDatabaseValue
  read(
    DistributedDatabaseContact      contact,
    DistributedDatabaseTransferType    type,
    DistributedDatabaseKey        ddb_key )
 
    throws DistributedDatabaseException
  {
    Object  o_key = ddb_key.getKey();
   
    try{
      byte[]  key = (byte[])o_key;
     
      HashWrapper  hw = new HashWrapper( key );
     
      synchronized( request_history ){
       
        if ( request_history.containsKey( hw )){
                   
          return( null );
        }
       
        request_history.put( hw, "" );
      }
     
      Map  request = BDecoder.decode( (byte[])o_key);
     
      log( "Received DDB request from " + contact.getName() + " - " + request );

      Map  result = receiveRequest( contact.getAddress(), request );
     
      return( ddb.createValue( BEncoder.encode( result )));
     
    }catch( Throwable e ){
     
      log( "DDB read failed", e );
     
      return( null );
    }
  }
 
  public void
  write(
    DistributedDatabaseContact      contact,
    DistributedDatabaseTransferType    type,
    DistributedDatabaseKey        key,
    DistributedDatabaseValue      value )
 
    throws DistributedDatabaseException
  {
    throw( new DistributedDatabaseException( "not supported" ));
  }
 
 
  public void
  log(
    String    str )
  {
    plugin.log( str );
  }
 
  public void
  log(
    String    str,
    Throwable  e )
  {
    plugin.log( str, e );
  }
 
 
  protected class
  testXferType
    implements DistributedDatabaseTransferType
 
  }
}
TOP

Related Classes of com.aelitis.azureus.plugins.net.netstatus.NetStatusProtocolTester

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.