Package org.gudy.azureus2.core3.tracker.client.impl

Source Code of org.gudy.azureus2.core3.tracker.client.impl.TRTrackerAnnouncerImpl

/*
* Created on 14-Feb-2005
* Created by Paul Gardner
* 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 org.gudy.azureus2.core3.tracker.client.impl;

import java.io.UnsupportedEncodingException;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import org.gudy.azureus2.core3.config.COConfigurationManager;
import org.gudy.azureus2.core3.internat.MessageText;
import org.gudy.azureus2.core3.logging.*;
import org.gudy.azureus2.core3.peer.PEPeerSource;
import org.gudy.azureus2.core3.torrent.TOTorrent;
import org.gudy.azureus2.core3.torrent.TOTorrentException;
import org.gudy.azureus2.core3.tracker.client.TRTrackerAnnouncer;
import org.gudy.azureus2.core3.tracker.client.TRTrackerAnnouncerException;
import org.gudy.azureus2.core3.tracker.client.TRTrackerAnnouncerListener;
import org.gudy.azureus2.core3.tracker.client.TRTrackerAnnouncerResponse;
import org.gudy.azureus2.core3.tracker.client.TRTrackerAnnouncerResponsePeer;
import org.gudy.azureus2.core3.util.AEMonitor;
import org.gudy.azureus2.core3.util.Constants;
import org.gudy.azureus2.core3.util.Debug;
import org.gudy.azureus2.core3.util.LightHashMap;
import org.gudy.azureus2.core3.util.ListenerManager;
import org.gudy.azureus2.core3.util.ListenerManagerDispatcher;
import org.gudy.azureus2.plugins.clientid.ClientIDException;
import org.gudy.azureus2.plugins.download.DownloadAnnounceResultPeer;
import org.gudy.azureus2.pluginsimpl.local.clientid.ClientIDManagerImpl;

import com.aelitis.azureus.core.tracker.TrackerPeerSource;
import com.aelitis.azureus.core.tracker.TrackerPeerSourceAdapter;

/**
* @author parg
*
*/

public abstract class
TRTrackerAnnouncerImpl
  implements TRTrackerAnnouncer
{
  // Used to be componentID 2
  public final static LogIDs LOGID = LogIDs.TRACKER;

  //   listener
 
  protected static final int LDT_TRACKER_RESPONSE    = 1;
  protected static final int LDT_URL_CHANGED      = 2;
  protected static final int LDT_URL_REFRESH      = 3;
 
  private static final String chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";

  private static final int       key_id_length  = 8;

  private static String
  createKeyID()
  {
    String  key_id = "";
   
    for (int i = 0; i < key_id_length; i++) {
      int pos = (int) ( Math.random() * chars.length());
        key_id +=  chars.charAt(pos);
    }
   
    return( key_id );
  }
 
  protected ListenerManager<TRTrackerAnnouncerListener>  listeners   = ListenerManager.createManager(
      "TrackerClient:ListenDispatcher",
      new ListenerManagerDispatcher<TRTrackerAnnouncerListener>()
      {
        public void
        dispatch(
          TRTrackerAnnouncerListener    listener,
          int                type,
          Object              value )
        {
          if ( type == LDT_TRACKER_RESPONSE ){
           
            listener.receivedTrackerResponse((TRTrackerAnnouncerResponse)value);
           
          }else if ( type == LDT_URL_CHANGED ){
           
            Object[]  x = (Object[])value;
           
            URL      old_url   = (URL)x[0];
            URL      new_url   = (URL)x[1];
            boolean    explicit  = ((Boolean)x[2]).booleanValue();
           
            listener.urlChanged( TRTrackerAnnouncerImpl.this, old_url, new_url, explicit );
           
          }else{
           
            listener.urlRefresh();
          }
        }
      });

  private Map  tracker_peer_cache    = new LinkedHashMap()// insertion order - most recent at end
  private AEMonitor tracker_peer_cache_mon   = new AEMonitor( "TRTrackerClientClassic:PC" );
  private int  cache_peers_used;
 
  final private TOTorrent            torrent;
  final private byte[]            peer_id;
  final private String            tracker_key;
  final private int              udp_key;
   
 
  protected
  TRTrackerAnnouncerImpl(
    TOTorrent  _torrent )
 
    throws TRTrackerAnnouncerException
  {
    torrent  = _torrent;
   
    tracker_key  = createKeyID();
     
    udp_key  = (int)(Math.random() 0xFFFFFFFFL );
   
    try{
      peer_id    = ClientIDManagerImpl.getSingleton().generatePeerID( torrent, false );
   
    }catch( ClientIDException e ){

       throw( new TRTrackerAnnouncerException( "TRTrackerAnnouncer: Peer ID generation fails", e ));
    }
  }

  public TOTorrent
  getTorrent()
  {
    return( torrent );
  }
 
  public Helper
  getHelper()
  {
    return(
      new Helper()
      {
        public byte[]
        getPeerID()
        {
          return( peer_id );
        }
       
        public String
        getTrackerKey()
        {
          return( tracker_key );
        }
       
        public int
        getUDPKey()
        {
          return( udp_key );
        }
       
        public void
        addToTrackerCache(
          TRTrackerAnnouncerResponsePeerImpl[]    peers )
        {
          TRTrackerAnnouncerImpl.this.addToTrackerCache( peers );
        }

        public TRTrackerAnnouncerResponsePeer[]
            getPeersFromCache(
              int      num_want )
        {
          return( TRTrackerAnnouncerImpl.this.getPeersFromCache(num_want));
        }
       
        public void
        setTrackerResponseCache(
          Map     map  )
        {
          TRTrackerAnnouncerImpl.this.setTrackerResponseCache( map );
        }
         
        public void
        removeFromTrackerResponseCache(
          String ip, int tcpPort )
        {
          TRTrackerAnnouncerImpl.this.removeFromTrackerResponseCache( ip,tcpPort );
        }
         
        public Map
        getTrackerResponseCache()
        {
          return( TRTrackerAnnouncerImpl.this.getTrackerResponseCache());
        }
         
        public void
        informResponse(
          TRTrackerAnnouncerHelper    helper,
          TRTrackerAnnouncerResponse    response )
        {
          TRTrackerAnnouncerImpl.this.informResponse( helper, response );
        }
       
        public void
        informURLChange(
          URL    old_url,
          URL    new_url,
          boolean  explicit )
        {
          listeners.dispatchLDT_URL_CHANGED,
              new Object[]{old_url, new_url, new Boolean(explicit)});
        }
       
        public void
        informURLRefresh()
        {
          TRTrackerAnnouncerImpl.this.informURLRefresh();
        }
       
         public void
        addListener(
          TRTrackerAnnouncerListener  l )
         {
           TRTrackerAnnouncerImpl.this.addListener( l );
         }
         
        public void
        removeListener(
          TRTrackerAnnouncerListener  l )
        {
          TRTrackerAnnouncerImpl.this.removeListener( l );
        }
      });
  }
 
  public byte[]
  getPeerId()
  {
    return( peer_id );
  }
 
   public static byte[]
  getAnonymousPeerId(
    String  my_ip,
    int    my_port )
  {
      byte[] anon_peer_id = new byte[20];
 
      // unique initial two bytes to identify this as fake

      anon_peer_id[0] = (byte)'[';
      anon_peer_id[1] = (byte)']';

      try{
        byte[]  ip_bytes   = my_ip.getBytes( Constants.DEFAULT_ENCODING );
        int    ip_len    = ip_bytes.length;
 
        if ( ip_len > 18 ){
   
          ip_len = 18;
        }
 
        System.arraycopy( ip_bytes, 0, anon_peer_id, 2, ip_len );
                 
        int  port_copy = my_port;
   
        for (int j=2+ip_len;j<20;j++){
     
          anon_peer_id[j] = (byte)(port_copy&0xff);
     
          port_copy >>= 8;
        }
      }catch( UnsupportedEncodingException e ){
       
        Debug.printStackTrace( e );
      }
     
      return( anon_peer_id );
   }
         
    // NOTE: tracker_cache is cleared out in DownloadManager when opening a torrent for the
    // first time as a DOS prevention measure
 
  public Map
  getTrackerResponseCache()
  {       
    return( exportTrackerCache());
  }
 
 
  public void
  setTrackerResponseCache(
    Map    map )
  {
    int  num = importTrackerCache( map );
   
    if (Logger.isEnabled())
      Logger.log(new LogEvent(getTorrent(), LOGID, "TRTrackerClient: imported "
          + num + " cached peers"));
  }
 
  protected Map
  exportTrackerCache()
  {
    Map  res = new LightHashMap(1);
   
    List  peers = new ArrayList();
   
    res.put( "tracker_peers", peers );
   
    try{
      tracker_peer_cache_mon.enter();
     
      Iterator it = tracker_peer_cache.values().iterator();
     
      while( it.hasNext()){
       
        TRTrackerAnnouncerResponsePeer  peer = (TRTrackerAnnouncerResponsePeer)it.next();   
 
        LightHashMap entry = new LightHashMap();
       
        entry.put( "ip", peer.getAddress().getBytes());
        entry.put( "src", peer.getSource().getBytes());
        entry.put( "port", new Long(peer.getPort()));
       
        int  udp_port = peer.getUDPPort();
        if ( udp_port != 0 ){
          entry.put( "udpport", new Long( udp_port));
        }
        int  http_port = peer.getHTTPPort();
        if ( http_port != 0 ){
          entry.put( "httpport", new Long( http_port));
        }
       
        entry.put( "prot", new Long(peer.getProtocol()));
       
        byte  az_ver = peer.getAZVersion();
       
        if ( az_ver != TRTrackerAnnouncer.AZ_TRACKER_VERSION_1 ){
          entry.put( "azver", new Long( az_ver ));
        }
       
        entry.compactify(0.9f);
       
        peers.add( entry );
      }
   
      if (Logger.isEnabled())
        Logger.log(new LogEvent(getTorrent(), LOGID,
            "TRTrackerClient: exported " + tracker_peer_cache.size()
                + " cached peers"));
    }finally{
     
      tracker_peer_cache_mon.exit();
    }
   
    return( res );
  }
 
  protected int
  importTrackerCache(
    Map    map )
  {
    if ( !COConfigurationManager.getBooleanParameter("File.save.peers.enable")){
     
      return( 0 );
    }
   
    try{
      if ( map == null ){
       
        return( 0 );
      }
     
      List  peers = (List)map.get( "tracker_peers" );
 
      if ( peers == null ){
       
        return( 0 );
      }
     
      try{
        tracker_peer_cache_mon.enter();
       
        for (int i=0;i<peers.size();i++){
         
          Map  peer = (Map)peers.get(i);
         
          byte[]  src_bytes = (byte[])peer.get("src");
          String  peer_source = src_bytes==null?PEPeerSource.PS_BT_TRACKER:new String(src_bytes);
          String  peer_ip_address = new String((byte[])peer.get("ip"));
          int    peer_tcp_port  = ((Long)peer.get("port")).intValue();
          byte[]  peer_peer_id  = getAnonymousPeerId( peer_ip_address, peer_tcp_port );
          Long  l_protocol    = (Long)peer.get( "prot" );
          short  protocol    = l_protocol==null?DownloadAnnounceResultPeer.PROTOCOL_NORMAL:l_protocol.shortValue();
          Long  l_udp_port    = (Long)peer.get("udpport");
          int    peer_udp_port  = l_udp_port==null?0:l_udp_port.intValue();
          Long  l_http_port    = (Long)peer.get("httpport");
          int    peer_http_port  = l_http_port==null?0:l_http_port.intValue();
          Long  l_az_ver    = (Long)peer.get("azver");
          byte  az_ver      = l_az_ver==null?TRTrackerAnnouncer.AZ_TRACKER_VERSION_1:l_az_ver.byteValue();
       
          //System.out.println( "recovered " + ip_address + ":" + port );
 
          TRTrackerAnnouncerResponsePeerImpl  entry =
            new TRTrackerAnnouncerResponsePeerImpl(
              peer_source,
              peer_peer_id,
              peer_ip_address,
              peer_tcp_port,
              peer_udp_port,
              peer_http_port,
              protocol,
              az_ver,
              (short)0 );
         
          tracker_peer_cache.put( entry.getKey(), entry );
        }
       
        return( tracker_peer_cache.size());
       
      }finally{
       
        tracker_peer_cache_mon.exit();
      }
    }catch( Throwable e ){
     
      Debug.printStackTrace( e );
     
      return( tracker_peer_cache.size());
    }
  }
 
  protected void
  addToTrackerCache(
    TRTrackerAnnouncerResponsePeerImpl[]    peers )
  {
    if ( !COConfigurationManager.getBooleanParameter("File.save.peers.enable")){
     
      return;
    }
   
    int  max = COConfigurationManager.getIntParameter( "File.save.peers.max", DEFAULT_PEERS_TO_CACHE );
   
    // System.out.println( "max peers= " + max );
   
    try{
      tracker_peer_cache_mon.enter();
     
      for (int i=0;i<peers.length;i++){
       
        TRTrackerAnnouncerResponsePeerImpl  peer = peers[i];
       
          // remove and reinsert to maintain most recent last
       
        tracker_peer_cache.remove( peer.getKey());
       
        tracker_peer_cache.put( peer.getKey(), peer );
      }
     
      Iterator  it = tracker_peer_cache.keySet().iterator();
     
      if ( max > 0 ){
         
        while ( tracker_peer_cache.size() > max ){
           
          it.next();
         
          it.remove();
        }
      }
    }finally{
     
      tracker_peer_cache_mon.exit();
    }
  }
 
  public void
  removeFromTrackerResponseCache(
    String    ip,
    int      tcp_port )
  {
    try{
      tracker_peer_cache_mon.enter();
   
        // create a fake peer so we can get the key
     
      TRTrackerAnnouncerResponsePeerImpl peer =
        new TRTrackerAnnouncerResponsePeerImpl( "", new byte[0], ip, tcp_port, 0, 0, (short)0, (byte)0, (short)0 );
     
      if ( tracker_peer_cache.remove( peer.getKey()) != null ){
       
        if (Logger.isEnabled())
          Logger.log(new LogEvent( getTorrent(), LOGID, "Explicit removal of peer cache for " + ip + ":" + tcp_port ));
      }
     
    }finally{
     
      tracker_peer_cache_mon.exit();
    }
  }
 
  public static Map
  mergeResponseCache(
    Map    map1,
    Map    map2 )
  {
    if ( map1 == null && map2 == null ){
      return( new HashMap());
    }else if ( map1 == null ){
      return( map2 );
    }else if ( map2 == null ){
      return( map1 );
    }
   
    Map  res = new HashMap();
       
    List  peers = (List)map1.get( "tracker_peers" );
   
    if ( peers == null ){
     
      peers = new ArrayList();
    }
   
    List  p2 = (List)map2.get( "tracker_peers" );
   
    if ( p2 != null ){
     
      if (Logger.isEnabled())
        Logger.log(new LogEvent(LOGID,
            "TRTrackerClient: merged peer sets: p1 = " + peers.size()
                + ", p2 = " + p2.size()));
   
      for (int i=0;i<p2.size();i++){
       
        peers.add( p2.get( i ));
      }
    }
   
    res.put( "tracker_peers", peers );
   
    return( res );
  }
 
  protected abstract int
  getPeerCacheLimit();
 
  protected TRTrackerAnnouncerResponsePeer[]
  getPeersFromCache(
    int  num_want )
  {
    int  limit = getPeerCacheLimit();
   
    if ( limit <= 0 ){
     
      return( new TRTrackerAnnouncerResponsePeer[0] );
    }
   
      // limit peers returned to avoid multi-tracker torrents from getting swamped
      // by out-of-date peers from a failed tracker
   
    num_want = Math.min( limit, num_want );
   
    try{
      tracker_peer_cache_mon.enter();
 
      TRTrackerAnnouncerResponsePeerImpl[]  res;
     
      if ( tracker_peer_cache.size() <= num_want ){
       
        res = new TRTrackerAnnouncerResponsePeerImpl[tracker_peer_cache.size()];
       
        tracker_peer_cache.values().toArray( res );
       
      }else{
     
        res = new TRTrackerAnnouncerResponsePeerImpl[num_want];
       
        Iterator  it = tracker_peer_cache.keySet().iterator();
       
          // take 'em out and put them back in so we cycle through the peers
          // over time
       
        for (int i=0;i<num_want;i++){
         
          String  key = (String)it.next();
         
          res[i] = (TRTrackerAnnouncerResponsePeerImpl)tracker_peer_cache.get(key);
       
          it.remove();
        }
       
        for (int i=0;i<num_want;i++){
         
          tracker_peer_cache.put( res[i].getKey(), res[i] );
        }
      }
     
      if (Logger.isEnabled()){
       
        for (int i=0;i<res.length;i++){
           
          Logger.log(new LogEvent(getTorrent(), LOGID, "CACHED PEER: " + res[i].getString()));
        }
     
        Logger.log(new LogEvent(getTorrent(), LOGID,
            "TRTrackerClient: returned " + res.length + " cached peers"));
      }
       
      cache_peers_used += res.length;
     
      return( res );
     
    }finally{
     
      tracker_peer_cache_mon.exit();
    }
  }
 
  public TrackerPeerSource
  getCacheTrackerPeerSource()
  {
    return(
      new TrackerPeerSourceAdapter()
      {
        public String
        getName()
        {
          return( MessageText.getString( "tps.tracker.cache1", new String[]{ String.valueOf( cache_peers_used )}));
        }
       
        public int
        getPeers()
        {
          return( tracker_peer_cache.size() );
        }
      });
  }

  protected void
  informResponse(
    TRTrackerAnnouncerHelper    helper,
    TRTrackerAnnouncerResponse    response )
  {
    listeners.dispatch( LDT_TRACKER_RESPONSE, response );
  }

  protected void
  informURLRefresh()
  {
    listeners.dispatch( LDT_URL_REFRESH, null );
  }
 
   public void
  addListener(
    TRTrackerAnnouncerListener  l )
  {
    listeners.addListener( l );
  }
   
  public void
  removeListener(
    TRTrackerAnnouncerListener  l )
  {
    listeners.removeListener(l);
  }

  public interface
  Helper
  {
    public byte[]
    getPeerID();
   
    public String
    getTrackerKey();
   
    public int
    getUDPKey();
   
    public void
    addToTrackerCache(
      TRTrackerAnnouncerResponsePeerImpl[]    peers );

    public TRTrackerAnnouncerResponsePeer[]
        getPeersFromCache(
          int      num_want );
   
    public void
    setTrackerResponseCache(
      Map map  );
   
    public void
    removeFromTrackerResponseCache(
      String ip, int tcpPort );
   
    public Map
    getTrackerResponseCache();
   
    public void
    informResponse(
      TRTrackerAnnouncerHelper    helper,
      TRTrackerAnnouncerResponse    response );
   
    public void
    informURLChange(
      URL      old_url,
      URL      new_url,
      boolean    explicit );
   
    public void
    informURLRefresh();
   
     public void
    addListener(
      TRTrackerAnnouncerListener  l );
     
    public void
    removeListener(
      TRTrackerAnnouncerListener  l );
  }
}
TOP

Related Classes of org.gudy.azureus2.core3.tracker.client.impl.TRTrackerAnnouncerImpl

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.