📄 trtrackerclientclassicimpl.java
字号:
if( peer_port < 0 || peer_port > 65535 ) {
LGLogger.log( LGLogger.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 ;
}
if ( PeerUtils.ignorePeerPort( peer_port )){
LGLogger.log(
componentID, evtFullTrace, LGLogger.INFORMATION,
"Ignoring " + ip + ":" + peer_port + " as peer port is in ignore list" );
}else{
valid_meta_peers.add(new TRTrackerResponsePeerImpl( peer_peer_id, ip, peer_port ));
}
}
}
}else{
// 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 ) {
LGLogger.log( LGLogger.ERROR, "Invalid compact peer port given: " +ip+ ": " +peer_port );
continue;
}
byte[] peer_peer_id = getAnonymousPeerId( ip, peer_port );
LGLogger.log(componentID, evtFullTrace, LGLogger.INFORMATION,
"COMPACT PEER: ip=" +ip+ " port=" +peer_port);
if ( PeerUtils.ignorePeerPort( peer_port )){
LGLogger.log(
componentID, evtFullTrace, LGLogger.INFORMATION,
" Ignoring as peer port is in ignore list" );
}else{
valid_meta_peers.add(new TRTrackerResponsePeerImpl( peer_peer_id, ip, peer_port ));
}
}
}
TRTrackerResponsePeer[] peers=new TRTrackerResponsePeer[valid_meta_peers.size()];
valid_meta_peers.toArray(peers);
addToTrackerCache( peers);
TRTrackerResponseImpl resp = new TRTrackerResponseImpl( TRTrackerResponse.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");
}
LGLogger.log(componentID, evtFullTrace, LGLogger.INFORMATION,
"ANNOUNCE SCRAPE2: seeds=" +complete_l+ " peers=" +incomplete_l);
}
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 now = SystemTime.getCurrentTime();
long lNewNextScrapeTime = now + 10*60*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( now );
if (lNextScrapeTime < lNewNextScrapeTime) {
scrapeResponse.setNextScrapeStartTime(lNewNextScrapeTime);
}
scrapeResponse.setSeedsPeers( complete, incomplete );
}
}
//resp.setScrapeDetails( lComplete.intValue(), lIncomplete.intValue());
}
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);
LGLogger.log("TRTrackerClient::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 TRTrackerResponseImpl( TRTrackerResponse.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 TRTrackerResponse
getLastResponse()
{
if( last_response == null ) {
return new TRTrackerResponseImpl(TRTrackerResponse.ST_OFFLINE, TRTrackerClient.REFRESH_MINIMUM_SECS );
}
return( last_response );
}
public void
addListener(
TRTrackerClientListener l )
{
listeners.addListener( l );
}
public void
removeListener(
TRTrackerClientListener l )
{
listeners.removeListener(l);
}
public void
destroy()
{
destroyed = true;
peer_server.removeListener( this );
COConfigurationManager.removeParameterListener("TCP.Announce.Port",this);
TRTrackerClientFactoryImpl.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 ){
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;
//use previously calculated interval if it's not time to update
if ( !SystemTime.isErrorLast1min() &&
((currentTime - failure_time_last_updated) < failure_added_time)) {
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 20min
if( !is_seed && failure_added_time > 1200) {
failure_added_time = 1200;
}
else if ( is_seed && failure_added_time > 3600) { //or 60min if seed
failure_added_time = 3600;
}
return failure_added_time;
}
protected 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 );
LGLogger.log(componentID, evtFullTrace, LGLogger.INFORMATION,
"TRTrackerClient: imported " + num + " cached peers" );
}
protected Map
exportTrackerCache()
{
Map res = new HashMap();
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()){
TRTrackerResponsePeer peer = (TRTrackerResponsePeer)it.next();
Map entry = new HashMap();
entry.put( "ip", peer.getIPAddress().getBytes());
entry.put( "port", new Long(peer.getPort()));
peers.add( entry );
}
LGLogger.log(componentID, evtFullTrace, LGLogger.INFORMATION,
"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);
String peer_ip_address = new String((byte[])peer.get("ip"));
int peer_port = ((Long)peer.get("port")).intValue();
byte[] peer_peer_id = getAnonymousPeerId( peer_ip_address, peer_port );
//System.out.println( "recovered " + ip_address + ":" + port );
if ( PeerUtils.ignorePeerPort( peer_port )){
LGLogger.log(
componentID, evtFullTrace, LGLogger.INFORMATION,
"Ignoring " + peer_ip_address + ":" + peer_port + " as peer port is in ignore list" );
}else{
tracker_peer_cache.put(
peer_ip_address,
new TRTrackerResponsePeerImpl(peer_peer_id, peer_ip_address, peer_port ));
}
}
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(
TRTrackerResponsePeer[] 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++){
TRTrackerResponsePeer peer = peers[i];
// remove and reinsert to maintain most recent last
tracker_peer_cache.remove( peer.getIPAddress());
tracker_peer_cache.put( peer.getIPAddress(), 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 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 ){
LGLogger.log(componentID, evtFullTrace, LGLogger.INFORMATION,
"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 TRTrackerResponsePeer[]
getPeersFromCache()
{
// use double the num_want as no doubt a fair few connections will fail and
// we want to get a decent reconnect rate
int num_want = calculateNumWant() * 4;
try{
tracker_peer_cache_mon.enter();
if ( tracker_peer_cache.size() <= num_want ){
TRTrackerResponsePeer[] res = new TRTrackerResponsePeer[tracker_peer_cache.size()];
tracker_peer_cache.values().toArray( res );
LGLogger.log(componentID, evtFullTrace, LGLogger.INFORMATION,
"TRTrackerClient: returned " + res.length + " cached peers" );
return( res );
}
TRTrackerResponsePeer[] res = new TRTrackerResponsePeer[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] = (TRTrackerResponsePeer)tracker_peer_cache.get(key);
it.remove();
}
for (int i=0;i<num_want;i++){
tracker_peer_cache.put( res[i].getIPAddress(), res[i] );
}
LGLogger.log(componentID, evtFullTrace, LGLogger.INFORMATION,
"TRTrackerClient: returned " + res.length + " cached peers" );
return( res );
}finally{
tracker_peer_cache_mon.exit();
}
}
// ParameterListener Implementation
public void parameterChanged(String parameterName) {
if("TCP.Announce.Port".equals(parameterName)) {
setPort();
}
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -