⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 trtrackerclientclassicimpl.java

📁 Azureus is a powerful, full-featured, cross-platform java BitTorrent client
💻 JAVA
📖 第 1 页 / 共 4 页
字号:
/*
 * File    : TRTrackerClientClassicImpl.java
 * Created : 5 Oct. 2003
 * By      : Parg 
 * 
 * Azureus - a Java Bittorrent client
 *
 * 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.
 *
 * 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 ( see the LICENSE file ).
 *
 * 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 org.gudy.azureus2.core3.tracker.client.classic;

import java.io.*;
import java.net.*;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.util.LinkedHashMap;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Random;

import javax.net.ssl.*;

import java.util.zip.*;

import org.gudy.azureus2.core3.logging.*;
import org.gudy.azureus2.core3.config.*;
import org.gudy.azureus2.core3.torrent.*;
import org.gudy.azureus2.core3.security.*;
import org.gudy.azureus2.core3.tracker.client.*;
import org.gudy.azureus2.core3.util.*;
import org.gudy.azureus2.core3.internat.*;
import org.gudy.azureus2.core3.peer.util.*;
import org.gudy.azureus2.core3.peer.PEPeerServer;
import org.gudy.azureus2.core3.peer.PEPeerServerListener;

import org.gudy.azureus2.core3.tracker.protocol.*;
import org.gudy.azureus2.core3.tracker.protocol.udp.*;
import org.gudy.azureus2.core3.tracker.util.impl.*;

import com.aelitis.azureus.core.proxy.AEProxyFactory;


/**
 * 
 * This class handles communication with the tracker
 * 
 * @author Olivier
 *
 */
public class 
TRTrackerClientClassicImpl
	implements TRTrackerClient, PEPeerServerListener, ParameterListener
{
	
		
	private static final int OVERRIDE_PERIOD			= 10*1000;
	 
	private static Timer	tracker_timer = new Timer( "Tracker Timer", 32);
	
	public static String 	UDP_REALM = "UDP Tracker";
	
	private TOTorrent				torrent;
	private PEPeerServer			peer_server;
	
	private TimerEvent				current_timer_event;
	private TimerEventPerformer		timer_event_action;
	
	private int					tracker_state 			= TS_INITIALISED;
	private String				tracker_status_str		= "";
	private TRTrackerResponse	last_response			= null;
	private long				last_update_time_secs;
	private long				current_time_to_wait_secs;
  
	private int  failure_added_time = 0;
    private long failure_time_last_updated = 0;
	
	private boolean			stopped;
	private boolean			completed;
	private boolean			complete_reported	= false;
	
	private boolean			update_in_progress	= false;
	
	private long			rd_last_override = 0;
	private int				rd_override_percentage	= 100;

  	private List trackerUrlLists;
     
  	private URL lastUsedUrl;
  
  	private String trackerUrlListString;
  
  	private byte[]				torrent_hash;
  	private PeerIdentityDataID	peer_data_id;
  	
	private String info_hash = "info_hash=";
	private byte[] tracker_peer_id;
	private String tracker_peer_id_str = "&peer_id=";
	
	private byte[] data_peer_id;
	
	private String 					key_id			= "";
	private static final int	   	key_id_length	= 8;
	private int						key_udp;
	
	private String port;
	private String ip_override;

	private String	last_warning_message	= "";
	
	private TrackerClientAnnounceDataProvider 	announce_data_provider;
	
	private Map	tracker_peer_cache		= new LinkedHashMap();	// insertion order - most recent at end
	private AEMonitor tracker_peer_cache_mon 	= new AEMonitor( "TRTrackerClientClassic:PC" );
	
	protected AEMonitor this_mon 	= new AEMonitor( "TRTrackerClientClassic" );

	private static final boolean	socks_peer_inform;

	private boolean	destroyed;
	
	
	static{
	 	socks_peer_inform	= 	
	  		COConfigurationManager.getBooleanParameter("Proxy.Data.Enable", false)&&
	 		COConfigurationManager.getBooleanParameter("Proxy.Data.SOCKS.inform", true );
	 }
	
	public final static int componentID = 2;
	public final static int evtLifeCycle = 0;
	public final static int evtFullTrace = 1;
	public final static int evtErrors = 2;

	// 	listener
	
	private static final int LDT_TRACKER_RESPONSE		= 1;
	private static final int LDT_URL_CHANGED			= 2;
	private static final int LDT_URL_REFRESH			= 3;
	
	private ListenerManager	listeners 	= ListenerManager.createManager(
			"TrackerClient:ListenDispatcher",
			new ListenerManagerDispatcher()
			{
				public void
				dispatch(
					Object		_listener,
					int			type,
					Object		value )
				{
					TRTrackerClientListener	listener = (TRTrackerClientListener)_listener;
					
					if ( type == LDT_TRACKER_RESPONSE ){
						
						listener.receivedTrackerResponse((TRTrackerResponse)value);
						
					}else if ( type == LDT_URL_CHANGED ){
						
						Object[]	x = (Object[])value;
						
						String		url 	= (String)x[0];
						boolean	explicit	= ((Boolean)x[1]).booleanValue();
						
						listener.urlChanged(url, explicit );
						
					}else{
						
						listener.urlRefresh();
					}
				}
			});

	static final String chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";

	public static byte[]
	createPeerID()
	{
		byte[] peerId = new byte[20];
	
		byte[] version = Constants.VERSION_ID;
    
		for (int i = 0; i < 8; i++) {
			peerId[i] = version[i];
		}
    
	 	for (int i = 8; i < 20; i++) {
		  int pos = (int) ( Math.random() * chars.length());
	     peerId[i] = (byte)chars.charAt(pos);
		}
	 	
		// System.out.println( "generated new peer id:" + ByteFormatter.nicePrint(peerId));

	 	return( peerId );
	}

	public 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 );
	}
	
  public 
  TRTrackerClientClassicImpl(
  	TOTorrent		_torrent,
  	PEPeerServer 	_peer_server ) 
  	
  	throws TRTrackerClientException
  {
  	torrent		= _torrent;
  	peer_server	= _peer_server;
  	
		//Get the Tracker url
		
	constructTrackerUrlLists( true );
       
		//Create our unique peerId
	
    tracker_peer_id = createPeerID();

    if ( COConfigurationManager.getBooleanParameter("Tracker Separate Peer IDs", false)){
    	
    	data_peer_id = createPeerID();
    	
    }else{
    	
    	data_peer_id	= tracker_peer_id;
    }

    key_id	= createKeyID();
    
	key_udp	= (int)(Math.random() *  (double)0xFFFFFFFFL );
	
	try {
	
		torrent_hash = _torrent.getHash();
		
		peer_data_id = PeerIdentityManager.createDataID( torrent_hash );
		
		this.info_hash += URLEncoder.encode(new String(torrent_hash, Constants.BYTE_ENCODING), Constants.BYTE_ENCODING).replaceAll("\\+", "%20");
	  
		this.tracker_peer_id_str += URLEncoder.encode(new String(tracker_peer_id, Constants.BYTE_ENCODING), Constants.BYTE_ENCODING).replaceAll("\\+", "%20");
	  
	}catch (UnsupportedEncodingException e){
		
		LGLogger.log(componentID, evtLifeCycle,"URL encode fails", e );
	  
	  throw( new TRTrackerClientException( "TRTrackerClient: URL encode fails"));
	  
	}catch( TOTorrentException e ){
	
		LGLogger.log(componentID, evtLifeCycle,"Torrent hash retrieval fails", e );
		
		throw( new TRTrackerClientException( "TRTrackerClient: URL encode fails"));	
	}
	
	peer_server.addListener( this );
	
  
  
	COConfigurationManager.addParameterListener("TCP.Announce.Port",this);
	
	setPort();
	   
	timer_event_action =  
		new TimerEventPerformer()
		{
			public void
			perform(
				TimerEvent	this_event )
			{
				long	secs_to_wait = getErrorRetryInterval();
							
				try{
															
					secs_to_wait = requestUpdateSupport();
								
				}finally{
						
					current_time_to_wait_secs	= secs_to_wait;
							
					if ( tracker_state == TS_STOPPED ){
						
						// System.out.println( "\tperform: stopped so no more events");
						
					}else{
						
					
						try{
							this_mon.enter();
						
								// it is possible that the current event was being processed
								// when another thread cancelled it and created a further timer
								// event. if this is the case we don't want to go ahead and
								// create another timer as one already exists 
								
							if ( this_event.isCancelled()){
								
								// System.out.println( "\tperform: cancelled so no new event");
								
							}else{
								
								
								secs_to_wait = getAdjustedSecsToWait();
								
								long target_time = SystemTime.getCurrentTime() + (secs_to_wait*1000);
								
								if ( current_timer_event != null && !current_timer_event.isCancelled()){
									
									if ( 	current_timer_event != this_event &&
											current_timer_event.getWhen() < target_time ){
									
											// existing event is earlier then current target, use it
												
										return;
									}
									
									current_timer_event.cancel();
								}
								
								if ( !destroyed ){
									
									current_timer_event = 
										tracker_timer.addEvent( target_time, this );
								}
							}
						}finally{
							
							this_mon.exit();
						}
					}
				}
			}
		};
    
		LGLogger.log(componentID, evtLifeCycle, LGLogger.INFORMATION, "Tracker Client Created using url : " + trackerUrlListString);
  }
	
	public void
	portChanged(
		int		new_port )
	{
		setPort();
		
		update( true );
	}
	
  	protected void
	setPort()
  	{
  			// we currently don't support incoming connections when SOCKs proxying
  		
  		int	port_num;
  		
  		if ( socks_peer_inform ){
  			
  			port_num	= 0;
  			
  		}else{
  		
  			port_num	= peer_server.getPort();
  		}
  		
  		String portOverride = COConfigurationManager.getStringParameter("TCP.Announce.Port","");
  		if(! portOverride.equals("")) {
  		  
  		  port = "&port=" + portOverride;
  		  
  		} else {
  		  
  		  port = "&port=" + port_num;
  		  
  		  //  BitComet extension for no incoming connections
  		
  		  if ( port_num == 0 ){
  			
  				port += "&hide=1";
  		  }
  		}

		
  	}
  	
	protected long
	getAdjustedSecsToWait()
	{

	  long		secs_to_wait = current_time_to_wait_secs;
													
	  if( last_response != null && last_response.getStatus() != TRTrackerResponse.ST_ONLINE ) {
      
	    secs_to_wait = getErrorRetryInterval();
							
	  }
    else{
        
      if( rd_override_percentage == 0 )  return REFRESH_MINIMUM_SECS;
							
      secs_to_wait = (secs_to_wait * rd_override_percentage) /100;
									
      if ( secs_to_wait < REFRESH_MINIMUM_SECS ){
	  			
        secs_to_wait = REFRESH_MINIMUM_SECS;
      }
    }
  		
	  return( secs_to_wait );
	}
  
	
	public int
  	getStatus()
  	{
  		return( tracker_state );
  	}
	
  	public String
  	getStatusString()
  	{
  		return( tracker_status_str );
  	}
  	
	public void
	setRefreshDelayOverrides(
		int		percentage )
	{
		if ( percentage > 100 ){
			
			percentage = 100;
			
		}else if ( percentage < 0 ){
			
			percentage	= 0;
		}
		
		long	now = SystemTime.getCurrentTime();
    //only start overriding once the tracker announce update has been called
    boolean override_allowed = rd_last_override > 0 && now - rd_last_override > OVERRIDE_PERIOD;
    
		if ( ( SystemTime.isErrorLast10sec() || override_allowed ) && rd_override_percentage != percentage ){
		
			try{
				this_mon.enter();

				rd_last_override	= now;
				
				rd_override_percentage	= percentage;
				
				if ( current_timer_event != null && !current_timer_event.isCancelled()){
					
					long	start 	= current_timer_event.getCreatedTime();
					long	expiry	= current_timer_event.getWhen();
					
					long	secs_to_wait = getAdjustedSecsToWait();
								
					long target_time = start + (secs_to_wait*1000);

					if ( target_time != expiry ){
						
						current_timer_event.cancel();
						
						if ( !destroyed ){ 
							
							current_timer_event = 
								tracker_timer.addEvent( 
									start,
									target_time,
									timer_event_action );	
						}
					}			
				}
			}finally{
				
				this_mon.exit();
			}
		}
	}
	
	public int
	getTimeUntilNextUpdate()
	{
		try{
			this_mon.enter();
		
			if ( current_timer_event == null ){
				
				return( getErrorRetryInterval() );
			}
					
			int rem = (int)((current_timer_event.getWhen() - SystemTime.getCurrentTime())/1000);
					
			return( rem );
			
		}finally{
			
			this_mon.exit();
		}
	}

	public int
	getLastUpdateTime()
	{
		return( (int)last_update_time_secs );
	}

	public void
	update(
		boolean		force )
	{
		long time = SystemTime.getCurrentTime() / 1000;

		if  ( SystemTime.isErrorLast1min() || force ||
			 	( time - last_update_time_secs >= REFRESH_MINIMUM_SECS )){
    		
			requestUpdate();
		}
	}
	
	public void
	complete(
		boolean	already_reported )
	{
		complete_reported	= (complete_reported || already_reported );
		
		completed			= true;
		
		requestUpdate();
	}
	
	public void
	stop()
	{
		stopped	= true;
        		
		requestUpdate();
	}
	
	protected void
	requestUpdate()
	{
		try{
			this_mon.enter();
			
			if ( current_timer_event != null ){
				
				current_timer_event.cancel();
			}
      
			rd_last_override = SystemTime.getCurrentTime();  //"pause" overrides for 10s
      
			if ( !destroyed ){
				
				current_timer_event = 
					tracker_timer.addEvent( 
						SystemTime.getCurrentTime(),
						timer_event_action );
			}
		}
    finally{
			this_mon.exit();
		}
	}
	
	protected long
	requestUpdateSupport()
	{
    
		boolean	clear_progress = true;
		
		try{
			try{
				this_mon.enter();

				if ( update_in_progress ){
					
					clear_progress = false;
					
					return( getErrorRetryInterval() );
				}
				
				update_in_progress = true;
				
			}finally{
				
				this_mon.exit();
			}
	
			last_update_time_secs	= SystemTime.getCurrentTime()/1000;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -