Package com.aelitis.azureus.plugins.tracker.local

Source Code of com.aelitis.azureus.plugins.tracker.local.LocalTrackerPlugin

/*
* Created on 23-Dec-2005
* Created by Paul Gardner
* Copyright (C) 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.plugins.tracker.local;

import java.io.PrintWriter;
import java.io.StringWriter;
import java.net.InetAddress;
import java.util.*;


import org.gudy.azureus2.core3.internat.MessageText;
import org.gudy.azureus2.core3.util.AERunnable;
import org.gudy.azureus2.core3.util.AsyncDispatcher;
import org.gudy.azureus2.core3.util.SHA1Simple;
import org.gudy.azureus2.core3.util.SystemTime;
import org.gudy.azureus2.core3.util.TorrentUtils;
import org.gudy.azureus2.plugins.*;
import org.gudy.azureus2.plugins.download.Download;
import org.gudy.azureus2.plugins.download.DownloadListener;
import org.gudy.azureus2.plugins.download.DownloadManagerListener;
import org.gudy.azureus2.plugins.logging.LoggerChannel;
import org.gudy.azureus2.plugins.logging.LoggerChannelListener;
import org.gudy.azureus2.plugins.peers.PeerManager;
import org.gudy.azureus2.plugins.torrent.Torrent;
import org.gudy.azureus2.plugins.torrent.TorrentAttribute;
import org.gudy.azureus2.plugins.ui.UIManager;
import org.gudy.azureus2.plugins.ui.config.BooleanParameter;
import org.gudy.azureus2.plugins.ui.config.ConfigSection;
import org.gudy.azureus2.plugins.ui.config.StringParameter;
import org.gudy.azureus2.plugins.ui.model.BasicPluginConfigModel;
import org.gudy.azureus2.plugins.ui.model.BasicPluginViewModel;
import org.gudy.azureus2.plugins.utils.*;
import org.gudy.azureus2.pluginsimpl.local.PluginCoreUtils;

import com.aelitis.azureus.core.AzureusCoreFactory;
import com.aelitis.azureus.core.instancemanager.AZInstance;
import com.aelitis.azureus.core.instancemanager.AZInstanceManager;
import com.aelitis.azureus.core.instancemanager.AZInstanceManagerListener;
import com.aelitis.azureus.core.instancemanager.AZInstanceTracked;
import com.aelitis.azureus.core.tracker.TrackerPeerSource;
import com.aelitis.azureus.core.tracker.TrackerPeerSourceAdapter;

public class
LocalTrackerPlugin
  implements Plugin, AZInstanceManagerListener, DownloadManagerListener, DownloadListener
{
  private static final String  PLUGIN_NAME  = "LAN Peer Finder";
  private static final String PLUGIN_CONFIGSECTION_ID = "Plugin.localtracker.name";
 
  private static final long  ANNOUNCE_PERIOD    = 5*60*1000;
  private static final long  RE_ANNOUNCE_PERIOD  = 1*60*1000;
 
  private PluginInterface    plugin_interface;
  private AZInstanceManager  instance_manager;
  private boolean        active;
  private TorrentAttribute   ta_networks;
  private TorrentAttribute   ta_peer_sources;

  private Map<Download,long[]>  downloads   = new HashMap<Download, long[]>();
 
  private Map<String,Map<String,Long>>  track_times  = new HashMap<String, Map<String,Long>>();
 
  private String        last_autoadd  = "";
  private String        last_subnets  = "";
 
  private BooleanParameter  enabled;
 
  private long        plugin_start_time;
 
  private long current_time;

  private LoggerChannel     log;
  private Monitor       mon;

  private AsyncDispatcher  dispatcher = new AsyncDispatcher( 30*1000 );
 
  public static void
  load(
    PluginInterface    plugin_interface )
  {
    plugin_interface.getPluginProperties().setProperty( "plugin.version",   "1.0" );
    plugin_interface.getPluginProperties().setProperty( "plugin.name",     PLUGIN_NAME );
  }
 
  public void
  initialize(
    PluginInterface   _plugin_interface )
  {
    plugin_interface  = _plugin_interface;
       
    ta_networks   = plugin_interface.getTorrentManager().getAttribute( TorrentAttribute.TA_NETWORKS );
    ta_peer_sources = plugin_interface.getTorrentManager().getAttribute( TorrentAttribute.TA_PEER_SOURCES );

    mon  = plugin_interface.getUtilities().getMonitor();
   
    log = plugin_interface.getLogger().getTimeStampedChannel(PLUGIN_NAME);
   
    UIManager  ui_manager = plugin_interface.getUIManager();
   
    BasicPluginConfigModel  config = ui_manager.createBasicPluginConfigModel( ConfigSection.SECTION_PLUGINS, PLUGIN_CONFIGSECTION_ID );

    config.addLabelParameter2( "Plugin.localtracker.info" );
   
    enabled = config.addBooleanParameter2( "Plugin.localtracker.enable", "Plugin.localtracker.enable", true );

    config.addLabelParameter2( "Plugin.localtracker.networks.info" );
   
    final StringParameter subnets = config.addStringParameter2( "Plugin.localtracker.networks", "Plugin.localtracker.networks", "" );

    final BooleanParameter include_wellknown = config.addBooleanParameter2( "Plugin.localtracker.wellknownlocals", "Plugin.localtracker.wellknownlocals", true );
   
    config.addLabelParameter2( "Plugin.localtracker.autoadd.info" );
   
    final StringParameter autoadd = config.addStringParameter2( "Plugin.localtracker.autoadd", "Plugin.localtracker.autoadd", "" );
   
    /*
     * actually these parameters affect LAN detection as a whole, not just the local tracker,
     * so leave them enabled...
     *
    enabled.addEnabledOnSelection( lp1 );
    enabled.addEnabledOnSelection( subnets );
    enabled.addEnabledOnSelection( lp2 );
    enabled.addEnabledOnSelection( autoadd );
    */
   
    final BasicPluginViewModel  view_model =
      plugin_interface.getUIManager().createBasicPluginViewModel( "Plugin.localtracker.name" );

    view_model.setConfigSectionID(PLUGIN_CONFIGSECTION_ID);
    view_model.getActivity().setVisible( false );
    view_model.getProgress().setVisible( false );
   
    log.addListener(
        new LoggerChannelListener()
        {
          public void
          messageLogged(
            int    type,
            String  content )
          {
            view_model.getLogArea().appendText( content + "\n" );
          }
         
          public void
          messageLogged(
            String    str,
            Throwable  error )
          {
            if ( str.length() > 0 ){
              view_model.getLogArea().appendText( str + "\n" );
            }
           
            StringWriter sw = new StringWriter();
           
            PrintWriter  pw = new PrintWriter( sw );
           
            error.printStackTrace( pw );
           
            pw.flush();
           
            view_model.getLogArea().appendText( sw.toString() + "\n" );
          }
        });
   
    plugin_start_time = plugin_interface.getUtilities().getCurrentSystemTime();

    // Assume we have a core, since this is a plugin
    instance_manager  = AzureusCoreFactory.getSingleton().getInstanceManager();
   
    instance_manager.addListener( this );
   
    plugin_interface.getPluginconfig().addListener(
        new PluginConfigListener()
        {
          public void
          configSaved()
          {
            processSubNets( subnets.getValue(),include_wellknown.getValue() );
            processAutoAdd( autoadd.getValue());
          }
        });
     
    processSubNets(subnets.getValue(), include_wellknown.getValue());
    processAutoAdd(autoadd.getValue());

    final DelayedTask dt = plugin_interface.getUtilities().createDelayedTask(new Runnable()
      {
        public void
        run()
        {
            plugin_interface.getDownloadManager().addListener(
                LocalTrackerPlugin.this );           
        }
      });
   
    dt.queue();
  }
 
  public void
  instanceFound(
    AZInstance    instance )
  {
    if ( !enabled.getValue()){
   
      return;
    }
   
    log.log( "Found: " + instance.getString());
   
    try{
      mon.enter();
     
      track_times.put( instance.getID(), new HashMap<String, Long>());
     
    }finally{
     
      mon.exit();
    }
   
    checkActivation();
  }
 
  protected void
  checkActivation()
  {
    try{
      mon.enter();
   
      if ( active ){
       
        return;
      }
     
      active  = true;
     
      plugin_interface.getUtilities().createThread(
        "Tracker",
        new Runnable()
        {
          public void
          run()
          {
            track();
          }
        });
     
    }finally{
     
      mon.exit();
    }
  }
 
  public void
  instanceChanged(
    AZInstance    instance )
  {
    if ( !enabled.getValue()){
     
      return;
    }
   
    log.log( "Changed: " + instance.getString());
  }
 
  public void
  instanceLost(
    AZInstance    instance )
  {
    try{
      mon.enter();
     
      track_times.remove( instance.getID());
     
    }finally{
     
      mon.exit();
    }
   
    if ( !enabled.getValue()){
     
      return;
    }
   
    log.log( "Lost: " + instance.getString());
  }
 
  public void
  instanceTracked(
    AZInstanceTracked     instance )
  {
    if ( !enabled.getValue()){
     
      return;
    }
   
    handleTrackResult( instance );
  }
 
  protected void
  track()
  {
    long  now = plugin_interface.getUtilities().getCurrentSystemTime();

    if ( now - plugin_start_time < 60*1000 ){
     
      try{
          // initial small delay to let things stabilise
       
        Thread.sleep( 15*1000 );
       
      }catch( Throwable e ){
      }
    }
       
   
    plugin_interface.getUtilities().createTimer( "LanPeerFinder:Tracker", true ).addPeriodicEvent(
        30*1000,
        new UTTimerEventPerformer() {
         
          public void perform( UTTimerEvent  event ) {
           
            current_time = plugin_interface.getUtilities().getCurrentSystemTime();

            try{
             
              List<Download>  todo = new ArrayList<Download>();
             
              try{
                mon.enter();
               
                Iterator<Map.Entry<Download,long[]>>  it = downloads.entrySet().iterator();
               
                while( it.hasNext()){
                 
                  Map.Entry<Download,long[]>  entry = it.next();
                 
                  Download  dl     = entry.getKey();
                  long    when  = entry.getValue()[0];
                 
                  if ( when > current_time || current_time - when > ANNOUNCE_PERIOD ){
                   
                    todo.add( dl );
                  }
                }

              }finally{
               
                mon.exit();
              }
             
              for (int i=0;i<todo.size();i++){
             
                track(todo.get(i));
              }
             
            }catch( Throwable e ){
             
              log.log(e);
            }
           
          }
   
        });
   
  }
 
 
 
  protected void
  track(
    Download  download )
  {
    long  now = plugin_interface.getUtilities().getCurrentSystemTime();

    boolean  ok = false;
   
    try{
      mon.enter();
     
      long[]  data = downloads.get( download );
     
      if ( data == null ){
       
        return;
      }
     
      long  last_track = data[0];
     
      if ( last_track > now || now - last_track > RE_ANNOUNCE_PERIOD ){
         
        ok  = true;
 
        data[0] = now;
      }
     
    }finally{
     
      mon.exit();
    }
   
    if ( ok ){
     
      trackSupport( download );
    }
  }
 
  protected void
  trackSupport(
    final Download  download )
  {
    if ( !enabled.getValue()){
     
      return;
    }
   
    int  state = download.getState();
   
    if ( state == Download.ST_ERROR || state == Download.ST_STOPPED ){
     
      return;
    }

    String[]  sources = download.getListAttribute( ta_peer_sources );
   
    boolean  ok = false;
   
    for (int i=0;i<sources.length;i++){
     
      if ( sources[i].equalsIgnoreCase( "Plugin")){
       
        ok  = true;
       
        break;
      }
    }
   
    if ( !ok ){
     
      return;
    }
   
    if ( download.getTorrent() == null ){
     
      return;
    }
   
    byte[] hash = new SHA1Simple().calculateHash(download.getTorrent().getHash());

   
    AZInstanceTracked[]  peers =
      instance_manager.track(
        hash,
        new AZInstanceTracked.TrackTarget()
        {
          public Object
          getTarget()
          {
            return( download );
          }
         
          public boolean
          isSeed()
          {
            return( download.isComplete());
          }
        });
   
    int  total_seeds   = 0;
    int  total_leechers  = 0;
    int  total_peers    = 0;
   
    for (int i=0;i<peers.length;i++){
     
      int res = handleTrackResult( peers[i] );
     
      if ( res == 1 ){
        total_seeds++;
      }else if ( res == 2 ){
        total_leechers++;
      }else if ( res == 3 ){
        total_seeds++;
        total_peers++;
      }else if ( res == 4 ){
        total_leechers++;
        total_peers++;
      }
    }
   
    try{
      mon.enter();

      long[] data = downloads.get( download );
     
      if ( data != null ){
       
        data[1] = total_seeds;
        data[2] = total_leechers;
        data[3] = total_peers;
      }
    }finally{
     
      mon.exit();
    }
  }
 
  protected void
  forceTrack(
    final Download  download )
  {
    try{
      mon.enter();

      long[] data = downloads.get( download );
     
      if ( data == null ){
       
        data = new long[4];
       
        downloads.put( download, data );
       
      }else{
     
        data[0] = 0;
      }
     
      String  dl_key = plugin_interface.getUtilities().getFormatters().encodeBytesToString(download.getTorrent().getHash());

      Iterator<Map<String,Long>>  it = track_times.values().iterator();
     
      while( it.hasNext()){
       
        it.next().remove( dl_key );
      }
    }finally{
     
      mon.exit();
    }
   
    dispatcher.dispatch(
      new AERunnable()
      {
        public void
        runSupport()
        {
          track( download );
        }
      });
  }
 
  protected int
  handleTrackResult(
    AZInstanceTracked    tracked_inst )
  {
    AZInstance  inst  = tracked_inst.getInstance();
   
    Download  download = (Download)tracked_inst.getTarget().getTarget();
       
    boolean  is_seed = tracked_inst.isSeed();
   
    long  now    = plugin_interface.getUtilities().getCurrentSystemTime();
   
    boolean  skip   = false;
   
      // this code is here to deal with multiple interface machines that receive the result multiple times
   
    try{
      mon.enter();
     
      Map<String,Long>  map = track_times.get( inst.getID() );
     
      if ( map == null ){
       
        map  = new HashMap<String, Long>();
       
        track_times.put( inst.getID(), map );
      }
     
      String  dl_key = plugin_interface.getUtilities().getFormatters().encodeBytesToString(download.getTorrent().getHash());
     
      Long  last_track = map.get( dl_key );
     
      if ( last_track != null ){
       
        long  lt = last_track.longValue();
       
        if ( now - lt < 30*1000 ){
         
          skip  = true;
        }
      }
     
      map.put( dl_key, new Long(now));
     
    }finally{
     
      mon.exit();
    }
   
    if ( skip ){
   
      return( -1 );
    }
   
    log.log( "Tracked: " + inst.getString() + ": " + download.getName() + ", seed = " + is_seed );

    if ( download.isComplete() && is_seed ){
     
      return( is_seed?1:0 );
    }
   
    PeerManager  peer_manager = download.getPeerManager();
   
    if ( peer_manager != null ){ 
     
      String  peer_ip      = inst.getInternalAddress().getHostAddress();
      int    peer_tcp_port  = inst.getTCPListenPort();
      int    peer_udp_port  = inst.getUDPListenPort();
     
      log.log( "    " + download.getName() + ": Injecting peer " + peer_ip + ":" + peer_tcp_port + "/" + peer_udp_port);
     
      peer_manager.addPeer( peer_ip, peer_tcp_port, peer_udp_port, false );
    }
   
    return( is_seed?3:2 );
  }
 
  public void
  downloadAdded(
    Download  download )
  {
    try{
      mon.enter();
   
      Torrent  torrent = download.getTorrent();
     
      if ( torrent == null ){
       
        return;
      }
     
      if ( TorrentUtils.isReallyPrivate(PluginCoreUtils.unwrap( torrent ))){
       
        log.log( "Not tracking " + download.getName() + ": torrent is private" );

        return;
      }
   
      String[]  networks = download.getListAttribute( ta_networks );
     
      boolean  public_net = false;
     
      for (int i=0;i<networks.length;i++){
       
        if ( networks[i].equalsIgnoreCase( "Public" )){
           
          public_net  = true;
         
          break;
        }
      }
     
      if ( !public_net ){
       
        log.log( "Not tracking " + download.getName() + ": torrent has no public network" );

        return;
      }

      if ( enabled.getValue()){
       
        log.log( "Tracking " + download.getName());
      }

      long[] data = downloads.get( download );
     
      if ( data == null ){
       
        data = new long[4];
       
        downloads.put( download, data );
       
      }else{
     
        data[0] = 0;
      }
     
      download.addListener( this );
     
    }finally{
     
      mon.exit();
    }
  }
 
  public void
  downloadRemoved(
    Download  download )
  {
    try{
      mon.enter();
   
      downloads.remove( download );
     
      download.removeListener( this );
     
    }finally{
     
      mon.exit();
    }
  }
 
  public TrackerPeerSource
  getTrackerPeerSource(
    final Download    download )
  {
    return(
      new TrackerPeerSourceAdapter()
      {
        private long[]     _last_data;
        private boolean    enabled;
        private boolean    running;
        private long    fixup_time;
       
        private long[]
        fixup()
        {
          long now = SystemTime.getMonotonousTime();
         
          if ( now - fixup_time > 1000 ){
           
            try{
              mon.enter();
 
              _last_data = downloads.get( download );
             
            }finally{
             
              mon.exit();
            }
           
            enabled = LocalTrackerPlugin.this.enabled.getValue();
           
            if ( enabled ){
             
              int ds = download.getState();
             
              running = ds == Download.ST_DOWNLOADING || ds == Download.ST_SEEDING;
             
            }else{
             
              running = false;
            }
           
            fixup_time = now;
          }
         
          return( _last_data );
        }
       
        public int
        getType()
        {
          return( TP_LAN );
        }
       
        public String
        getName()
        {
          return( MessageText.getString( "tps.lan.details", new String[]{ String.valueOf( instance_manager.getOtherInstanceCount())}));
        }
       
        public int
        getStatus()
        {
          long[] last_data = fixup();
         
          if ( last_data == null || !enabled ){
           
            return( ST_DISABLED );
          }
         
          if ( running ){
           
            return( ST_ONLINE );
          }
         
          return( ST_STOPPED );
        }
       
        public int
        getSeedCount()
        {
          long[] last_data = fixup();
         
          if ( last_data == null || !running ){
           
            return( -1 );
          }
         
          return((int)last_data[1] );
        }
       
        public int
        getLeecherCount()
        {
          long[] last_data = fixup();
         
          if ( last_data == null || !running ){
           
            return( -1 );
          }
         
          return((int)last_data[2] );
        }
       
        public int
        getPeers()
        {
          long[] last_data = fixup();
         
          if ( last_data == null || !running ){
           
            return( -1 );
          }
         
          return((int)last_data[3] );
        }
       
        public int
        getSecondsToUpdate()
        {
          long[] last_data = fixup();
         
          if ( last_data == null || !running ){
           
            return( Integer.MIN_VALUE );
          }
         
          return((int)(( ANNOUNCE_PERIOD - ( SystemTime.getCurrentTime() - last_data[0] ))/1000 ));
        }
       
        public int
        getInterval()
        {
          if ( running ){
         
            return((int)( ANNOUNCE_PERIOD/1000 ));
          }
         
          return( -1 );
        }
       
        public int
        getMinInterval()
        {
          if ( running ){
         
            return((int)( RE_ANNOUNCE_PERIOD/1000 ));
          }
         
          return( -1 );
        }
       
        public boolean
        isUpdating()
        {
          int  su = getSecondsToUpdate();
         
          if ( su == Integer.MIN_VALUE || su >= 0 ){
           
            return( false );
          }
         
          return( true );
        }
      });
  }
 
  public void
  stateChanged(
    Download    download,
    int        old_state,
    int        new_state )
  {
    if (   new_state == Download.ST_DOWNLOADING ||
        new_state == Download.ST_SEEDING ){
     
      forceTrack( download );
    }
  }
 
  public void
  positionChanged(
    Download  download,
    int oldPosition,
    int newPosition )
  {
  }
 
  protected void
  processSubNets(
    String  subnets,
    boolean  include_well_known )
  {
    if ( include_well_known != instance_manager.getIncludeWellKnownLANs()){
   
      instance_manager.setIncludeWellKnownLANs( include_well_known );
     
      log.log( "Include well known local networks set to " + include_well_known );
    }
   
    if ( subnets.equals( last_subnets )){
     
      return;
    }
   
    last_subnets = subnets;
   
    StringTokenizer  tok = new StringTokenizer( subnets, ";");
       
    while( tok.hasMoreTokens()){
     
      String  net = tok.nextToken().trim();
       
      try{
       
        if ( instance_manager.addLANSubnet( net )){
       
          log.log( "Added network '" + net + "'" );
        }
               
      }catch( Throwable e ){
       
        log.log( "Failed to add network '" + net + "'", e );
      }
    }
  }
 
  protected void
  processAutoAdd(
    String  autoadd )
  {
    if ( autoadd.equals( last_autoadd )){
     
      return;
    }
   
    last_autoadd = autoadd;
   
    StringTokenizer  tok = new StringTokenizer( autoadd, ";");
         
    while( tok.hasMoreTokens()){
     
      String  peer = tok.nextToken();
       
      try{
       
        InetAddress p = InetAddress.getByName( peer.trim());
       
        if ( instance_manager.addInstance( p )){
       
          log.log( "Added peer '" + peer + "'" );
        }
      }catch( Throwable e ){
       
        log.log( "Failed to decode peer '" + peer + "'", e );
      }
    }
  }
}
TOP

Related Classes of com.aelitis.azureus.plugins.tracker.local.LocalTrackerPlugin

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.