📄 trtrackerbtannouncerimpl.java
字号:
}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 + -