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

📄 trtrackerbtannouncerimpl.java

📁 基于JXTA开发平台的下载软件开发源代码
💻 JAVA
📖 第 1 页 / 共 5 页
字号:
								}finally{
									
									class_mon.exit();
								}
								
								if ( log_it ){
		 							Logger.logTextResource(new LogAlert(LogAlert.UNREPEATABLE,
											LogAlert.AT_WARNING,
											"TrackerClient.announce.warningmessage"), new String[] {
											announce_data_provider.getName(), warning_message });
		 						}
							}
	 					}
	 				}catch( Throwable e ){
	 					
	 					Debug.printStackTrace( e );
	 				}
	 				
					long	time_to_wait;
										
					try {
						time_to_wait = ((Long) metaData.get("interval")).longValue();

						// guard against crazy return values
						if (time_to_wait < 0 || time_to_wait > 0xffffffffL) {
							time_to_wait = 0xffffffffL;
						}

						Long raw_min_interval = (Long) metaData.get("min interval");
						if (raw_min_interval != null) {
							min_interval = raw_min_interval.longValue();

							// ignore useless values
							// Note: Many trackers set min_interval and interval the same.
							if (min_interval < 1 || min_interval > time_to_wait) {
								min_interval = 0;
							}
						}

						// roll back 10 seconds to make sure we announce before the tracker
						// times us out.  This is done after min_interval in order not to 
						// mess up the "ignore useless values"
						if (time_to_wait > 30)
							time_to_wait -= 10;

					} catch (Exception e) {
				   	
				     byte[]	failure_reason_bytes = (byte[]) metaData.get("failure reason");
						
				     if ( failure_reason_bytes == null ){
							
				    	 if (Logger.isEnabled())
								Logger.log(new LogEvent(torrent, LOGID, LogEvent.LT_WARNING,
										"Problems with Tracker, will retry in "
												+ getErrorRetryInterval() + "ms"));
											   			
				       return( new TRTrackerAnnouncerResponseImpl( url, torrent_hash, TRTrackerAnnouncerResponse.ST_OFFLINE, getErrorRetryInterval(), "Unknown cause" ));
	
				     }else{
				     	
				     		// explicit failure from the tracker
				     	
				       failure_reason = new String( failure_reason_bytes, Constants.DEFAULT_ENCODING);
                            				
				       return( new TRTrackerAnnouncerResponseImpl( url, torrent_hash, TRTrackerAnnouncerResponse.ST_REPORTED_ERROR, getErrorRetryInterval(), failure_reason ));
				     }
				   }
				   
				   	//System.out.println("Response from Announce: " + new String(data));
				   
				   Long incomplete_l 	= (Long)metaData.get("incomplete");
				   Long complete_l 		= (Long)metaData.get("complete");
				   
				   if ( incomplete_l != null || complete_l != null  ){
				   
				  	 if (Logger.isEnabled())
							Logger.log(new LogEvent(torrent, LOGID,
									"ANNOUNCE SCRAPE1: seeds=" + complete_l + " peers="
											+ incomplete_l));
				   }
           
           
			           //TrackerID extension, used by phpbt trackers.
			           //We reply with '&trackerid=1234' when we receive
			           //'10:tracker id4:1234e' on announce reply.
			           //NOTE: we receive as 'tracker id' but reply as 'trackerid'
			           byte[] trackerid = (byte[])metaData.get( "tracker id" );
			           if( trackerid != null ) {
			             tracker_id = new String( trackerid );
			           }
			           
           						
						//build the list of peers
					List valid_meta_peers = new ArrayList();
						
				    Object	meta_peers_peek = metaData.get( "peers" );
				    
				    	// list for non-compact returns
				    
				    if ( meta_peers_peek instanceof List ){
				    	
				    	
						List meta_peers = (List)meta_peers_peek;
						 					 
						
							//for every peer
						int peers_length = meta_peers.size();
							
						for (int i = 0; i < peers_length; i++) {
							 	
							Map peer = (Map) meta_peers.get(i);
							   						
							Object s_peerid	= peer.get("peer id"); 
							Object s_ip		= peer.get("ip"); 
							Object s_port	= peer.get("port"); 
													
								// Assert that all ip and port are available
							
							if ( s_ip != null && s_port != null ){
					
									//get the peer ip address
								
								String ip = new String((byte[]) s_ip, Constants.DEFAULT_ENCODING); 
								
									//get the peer port number
								
								int peer_port = ((Long) s_port).intValue(); 
				                
                if (peer_port < 0 || peer_port > 65535) {
                	if (Logger.isEnabled())
										Logger.log(new LogEvent(torrent, LOGID, LogEvent.LT_ERROR,
												"Invalid peer port given: " + ip + ": " + peer_port));
                  continue;
                }
								
								byte[] peer_peer_id;
								
								// extension - if peer id is missing then the tracker isn't sending
								// peer ids to save on bandwidth. However, we need something "unique" to 
								// work on internally so make an ID up from the ip and port
								
								if ( s_peerid == null ){
	                
									// Debug.out(ip + ": tracker did not give peerID in reply");

									peer_peer_id = getAnonymousPeerId( ip, peer_port );
									
									// System.out.println("generated peer id" + new String(peerId) + "/" + ByteFormatter.nicePrint( peerId, true ));
								}else{
								
									peer_peer_id = (byte[])s_peerid ; 
								}
								
								short protocol = TRTrackerAnnouncerResponsePeer.PROTOCOL_NORMAL;
								
								if (Logger.isEnabled())
									Logger.log(new LogEvent(torrent, LOGID,
											"NON-COMPACT PEER: ip=" + ip + ",port=" + peer_port + ",prot=" + protocol));

								valid_meta_peers.add(
									new TRTrackerAnnouncerResponsePeerImpl( 
											PEPeerSource.PS_BT_TRACKER, 
											peer_peer_id, 
											ip, 
											peer_port,
											protocol  ));
								
							} 
						}
				    }else if ( meta_peers_peek instanceof byte[] ){
				    	
				    		// byte[] for compact returns
				    	
				    
				    	byte[]	meta_peers = (byte[])meta_peers_peek;
				    	
				    	for (int i=0;i<meta_peers.length;i+=6){
				    		
				    		int	ip1 = 0xFF & meta_peers[i];
				    		int	ip2 = 0xFF & meta_peers[i+1];
				    		int	ip3 = 0xFF & meta_peers[i+2];
				    		int	ip4 = 0xFF & meta_peers[i+3];
				    		int	po1 = 0xFF & meta_peers[i+4];
				    		int	po2 = 0xFF & meta_peers[i+5];
				    		
				    		String	ip 		= "" + ip1 + "." + ip2 + "." + ip3 + "." + ip4;
				    		int		peer_port 	= po1*256+po2;
				    		
                if (peer_port < 0 || peer_port > 65535) {
                	if (Logger.isEnabled())
										Logger.log(new LogEvent(torrent, LOGID, LogEvent.LT_ERROR,
												"Invalid compact peer port given: " + ip + ": "
														+ peer_port));
                  continue;
                }
                
				    		byte[]	peer_peer_id = getAnonymousPeerId( ip, peer_port );
							
				    		short protocol = TRTrackerAnnouncerResponsePeer.PROTOCOL_NORMAL;
				    		
				    		if (Logger.isEnabled())
									Logger.log(new LogEvent(torrent, LOGID, "COMPACT PEER: ip="
											+ ip + ",port=" + peer_port + ",prot=" + protocol ));

				    		valid_meta_peers.add(
				    			new TRTrackerAnnouncerResponsePeerImpl( 
				    					PEPeerSource.PS_BT_TRACKER, 
				    					peer_peer_id, 
				    					ip, 
				    					peer_port,
				    					protocol ));
                			
				    	}
				    }else{
						
						throw( new IOException( "peers missing from response" ));
				    }
				    
					TRTrackerAnnouncerResponsePeer[] peers=new TRTrackerAnnouncerResponsePeer[valid_meta_peers.size()];
					
					valid_meta_peers.toArray(peers);
					
					addToTrackerCache( peers);
					
					TRTrackerAnnouncerResponseImpl resp = new TRTrackerAnnouncerResponseImpl( url, torrent_hash, TRTrackerAnnouncerResponse.ST_ONLINE, time_to_wait, peers );
          
						//reset failure retry interval on successful connect
					
					failure_added_time = 0;
					
					Map extensions = (Map)metaData.get( "extensions" );
					
					resp.setExtensions(extensions);
					
					if ( extensions != null ){
						
						if ( complete_l == null) {
							complete_l = (Long)extensions.get("complete");
						}
						
						if ( incomplete_l == null) {
							incomplete_l = (Long)extensions.get("incomplete");
						}
					
						if (Logger.isEnabled())
							Logger.log(new LogEvent(torrent, LOGID,
									"ANNOUNCE SCRAPE2: seeds=" + complete_l + " peers="
											+ incomplete_l));
			            
						Object	override = extensions.get( "min interval override" );
						
						if ( override != null && override instanceof Long ){
							
								// this is to allow specific torrents to be refreshed more quickly
								// if the tracker permits. Parg
							
							min_interval_override = ((Long)override).longValue();
						}
					}

					if (complete_l != null || incomplete_l != null) {

						int complete = complete_l == null ? 0 : complete_l.intValue();

						int incomplete = incomplete_l == null ? 0 : incomplete_l.intValue();

						TRTrackerScraper scraper = TRTrackerScraperFactory.getSingleton();

						if (scraper != null) {
							TRTrackerScraperResponse scrapeResponse = scraper.scrape(this);
							if (scrapeResponse != null) {
								long lNextScrapeTime = scrapeResponse.getNextScrapeStartTime();
								long lNewNextScrapeTime = TRTrackerScraperResponseImpl
										.calcScrapeIntervalSecs(0, complete) * 1000;

								// make it look as if the scrape has just run. Important
								// as seeding rules may make calculations on when the 
								// scrape value were set

								scrapeResponse.setScrapeStartTime(SystemTime.getCurrentTime());

								if (lNextScrapeTime < lNewNextScrapeTime)
									scrapeResponse.setNextScrapeStartTime(lNewNextScrapeTime);

								scrapeResponse.setSeedsPeers(complete, incomplete);
							}
						}
					}

					return (resp);  

				}catch( IOException e ){
					
						// decode could fail if the tracker's returned, say, an HTTP response
						// indicating server overload
	 				 				
	 				String	trace_data = new String(data);
	 				
	 				if (Logger.isEnabled())
						Logger.log(new LogEvent(torrent, LOGID, LogEvent.LT_ERROR,
								"TRTrackerAnnouncer::invalid reply: " + trace_data));
	 				
	 				if ( trace_data.length() > 150 ){
	 					
	 					trace_data = trace_data.substring(0,150) + "...";
	 				}
	 				
	 				failure_reason = "invalid reply: " + trace_data;
	 			}	 				
	 		}catch( Throwable e ){
				
	 			Debug.printStackTrace( e );
				
				failure_reason = "error: " + e.getMessage();
			}
  		}

		return( new TRTrackerAnnouncerResponseImpl( url, torrent_hash, TRTrackerAnnouncerResponse.ST_OFFLINE, getErrorRetryInterval(), failure_reason ));
  	}
  	
	protected void
	informURLChange(
		URL		url,
		boolean	explicit  )
	{
		listeners.dispatch(	LDT_URL_CHANGED,
							new Object[]{url.toString(),new Boolean(explicit)});
	}
	
	protected void
	informURLRefresh()
	{
		listeners.dispatch( LDT_URL_REFRESH, null );		
	}
	
	public TRTrackerAnnouncerResponse
	getLastResponse()
	{
		if( last_response == null ){
			
			return new TRTrackerAnnouncerResponseImpl( null, torrent_hash, TRTrackerAnnouncerResponse.ST_OFFLINE, TRTrackerAnnouncer.REFRESH_MINIMUM_SECS, "Initialising" );
		}
		
		return( last_response );
	}
	
 
	public void
	destroy()
	{       
		destroyed	= true;

		COConfigurationManager.removeParameterListener("TCP.Announce.Port",this);
		
		TRTrackerAnnouncerFactoryImpl.destroy( this );
		
		try{
			this_mon.enter();
			
			if ( current_timer_event != null ){
				
					// cancel any events that are a way off being triggered. note that
					// we don't want to cancel all events as the "stopped" event that
					// is scheduled on stop of a download may still be lurking
				
				if ( current_timer_event.getWhen() - SystemTime.getCurrentTime() > 10*1000 ){
					
					if (Logger.isEnabled())
						Logger.log(new LogEvent(torrent, LOGID,
								"Canceling announce trigger"));

					current_timer_event.cancel();
				}
			}
		}finally{
			
			this_mon.exit();
		}
	}
  
  
  /**
   * Retrieve the retry interval to use on announce errors.
   */
  private int getErrorRetryInterval() {
    
    long currentTime = SystemTime.getCurrentTime() /1000;
        
    long diff = currentTime - failure_time_last_updated;
    
    //use previously calculated interval if it's not time to update
    if( diff < failure_added_time && !(diff < 0) ) {
      return failure_added_time;
    }

    //update previous change time
    failure_time_last_updated = currentTime;
    
    if( failure_added_time == 0 ) { //start
      failure_added_time = 10;
    }
    else if( failure_added_time < 30 ) {
      //three 10-sec retries
      failure_added_time += 10;
    }
    else if( failure_added_time < 60 ) {
      //two 15-sec retries
      failure_added_time += 15;
    }
    else if( failure_added_time < 120 ) {
      //two 30-sec retries
      failure_added_time += 30;
    }
    else if( failure_added_time < 600 ) {
      //eight 60-sec retries
      failure_added_time += 60;
    }
    else {
      //2-3min random retry 
      failure_added_time += 120 + new Random().nextInt( 60 );
    }

    boolean is_seed = (announce_data_provider == null) ? false : announce_data_provider.getRemaining() == 0;
    
    if( is_seed ) failure_added_time = failure_added_time * 2; //no need to retry as often
    
    //make sure we're not waiting longer than 30min
    if( !is_seed && failure_added_time > 1800) {
      failure_added_time = 1800;
    }
    else if ( is_seed && failure_added_time > 3600) { //or 60min if seed
      failure_added_time = 3600;
    }

    return failure_added_time;
  }
  
 
	public void
	setAnnounceResult(
		DownloadAnnounceResult	result )
	{
			// this is how the results from "external" announces get into the system
			// really should refactor so that "normal" and "external" mechanisms are
			// just instances of the same generic approach
		
		TRTrackerAnnouncerResponseImpl 	response;
		String							status;
		
		if ( result.getResponseType() == DownloadAnnounceResult.RT_ERROR ){
			
			status = MessageText.getString("PeerManager.status.error"); 
		      
			String	reason = result.getError();
	
			if ( reason != null ){
		
				status += " (" + reason + ")";		
			}
			
	  		response = new TRTrackerAnnouncerResponseImpl(
				  				result.getURL(),
				  				torrent_hash,
				  				TRTrackerAnnouncerResponse.ST_OFFLINE, 
								result.getTimeToWait(), 
								reason );
		}else{
			DownloadAnnounceResultPeer[]	ext_peers = result.getPeers();
			
			TRTrackerAnnouncerResponsePeer[] peers = new TRTrackerAnnouncerResponsePeer[ext_peers.length];
				
			for (int i=0;i<ext_peers.length;i++){
				
				DownloadAnnounceResultPeer	ext_peer = ext_peers[i];
				
				if (Logger.isEnabled())
					Logger.log(new LogEvent(torrent, LOGID, "EXTERNAL PEER: ip="
							+ ext_peer.getAddress() + ",port=" + ext_peer.getPort()+",prot=" + ext_peer.getProtocol()));

				peers[i] = new TRTrackerAnnouncerResponsePeerImpl( 
								ext_peer.getSource(),
								ext_peer.getPeerID(),
								ext_peer.getAddress(), 
								ext_peer.getPort(),
								ext_peer.getProtocol());
			}
			
			addToTrackerCache( peers);
		
			status = MessageText.getString("PeerManager.status.ok");

			response = new TRTrackerAnnouncerResponseImpl( result.getURL(), torrent_hash, TRTrackerAnnouncerResponse.ST_ONLINE, result.getTimeToWait(), peers );
		}
		
			// only make the user aware of the status if the underlying announce

⌨️ 快捷键说明

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