protected void checkActivation(boolean force) { synchronized (this) { int next_check_delay; if (destroyed || stopped || announcers.size() <= activated.size()) { return; } if (provider == null) { next_check_delay = ACT_CHECK_INIT_DELAY; } else { boolean activate = force; boolean seeding = provider.getRemaining() == 0; if (seeding && activated.size() > 0) { // when seeding we only activate on tracker fail or major lack of connections // as normally we rely on downloaders rotating and finding us int connected = provider.getConnectedConnectionCount(); if (connected < 1) { activate = SystemTime.getMonotonousTime() - last_activation_time >= 60 * 1000; next_check_delay = ACT_CHECK_SEEDING_SHORT_DELAY; } else if (connected < 3) { next_check_delay = ACT_CHECK_SEEDING_LONG_DELAY; } else { next_check_delay = 0; } } else { int allowed = provider.getMaxNewConnectionsAllowed(); int pending = provider.getPendingConnectionCount(); int connected = provider.getConnectedConnectionCount(); int online = 0; for (TRTrackerAnnouncerHelper a : activated) { TRTrackerAnnouncerResponse response = a.getLastResponse(); if (response != null && response.getStatus() == TRTrackerAnnouncerResponse.ST_ONLINE) { online++; } } /* System.out.println( "checkActivation: announcers=" + announcers.size() + ", active=" + activated.size() + ", online=" + online + ", allowed=" + allowed + ", pending=" + pending + ", connected=" + connected + ", seeding=" + seeding ); */ if (online == 0) { activate = true; // no trackers online, start next and recheck soon next_check_delay = ACT_CHECK_INIT_DELAY; } else { int potential = connected + pending; if (potential < 10) { // minimal connectivity activate = true; next_check_delay = ACT_CHECK_INIT_DELAY; } else if (allowed >= 5 && pending < 3 * allowed / 4) { // not enough to fulfill our needs activate = true; next_check_delay = ACT_CHECK_INTERIM_DELAY; } else { // things look good, recheck in a bit next_check_delay = ACT_CHECK_IDLE_DELAY; } } } if (activate) { for (TRTrackerAnnouncerHelper a : announcers) { if (!activated.contains(a)) { if (Logger.isEnabled()) { Logger.log( new LogEvent( getTorrent(), LOGID, "Activating " + getString(a.getAnnounceSets()))); } activated.add(a); last_activation_time = SystemTime.getMonotonousTime(); if (complete) { a.complete(true); } else { a.update(false); } break; } } } } if (next_check_delay > 0) { setupActivationCheck(next_check_delay); } } }
protected void split() throws TRTrackerAnnouncerException { String[] networks = f_provider == null ? null : f_provider.getNetworks(); TRTrackerAnnouncerHelper to_activate = null; synchronized (this) { if (stopped || destroyed) { return; } TOTorrent torrent = getTorrent(); TOTorrentAnnounceURLSet[] sets = torrent.getAnnounceURLGroup().getAnnounceURLSets(); // sanitise dht entries if (sets.length == 0) { sets = new TOTorrentAnnounceURLSet[] { torrent .getAnnounceURLGroup() .createAnnounceURLSet(new URL[] {torrent.getAnnounceURL()}) }; } else { boolean found_decentralised = false; boolean modified = false; for (int i = 0; i < sets.length; i++) { TOTorrentAnnounceURLSet set = sets[i]; URL[] urls = set.getAnnounceURLs().clone(); for (int j = 0; j < urls.length; j++) { URL u = urls[j]; if (u != null && TorrentUtils.isDecentralised(u)) { if (found_decentralised) { modified = true; urls[j] = null; } else { found_decentralised = true; } } } } if (modified) { List<TOTorrentAnnounceURLSet> s_list = new ArrayList<TOTorrentAnnounceURLSet>(); for (TOTorrentAnnounceURLSet set : sets) { URL[] urls = set.getAnnounceURLs(); List<URL> u_list = new ArrayList<URL>(urls.length); for (URL u : urls) { if (u != null) { u_list.add(u); } } if (u_list.size() > 0) { s_list.add( torrent .getAnnounceURLGroup() .createAnnounceURLSet(u_list.toArray(new URL[u_list.size()]))); } } sets = s_list.toArray(new TOTorrentAnnounceURLSet[s_list.size()]); } } List<TOTorrentAnnounceURLSet[]> new_sets = new ArrayList<TOTorrentAnnounceURLSet[]>(); if (is_manual || sets.length < 2) { new_sets.add(sets); } else { List<TOTorrentAnnounceURLSet> list = new ArrayList<TOTorrentAnnounceURLSet>(Arrays.asList(sets)); // often we have http:/xxxx/ and udp:/xxxx/ as separate groups - keep these together while (list.size() > 0) { TOTorrentAnnounceURLSet set1 = list.remove(0); boolean done = false; URL[] urls1 = set1.getAnnounceURLs(); if (urls1.length == 1) { URL url1 = urls1[0]; String prot1 = url1.getProtocol().toLowerCase(); String host1 = url1.getHost(); for (int i = 0; i < list.size(); i++) { TOTorrentAnnounceURLSet set2 = list.get(i); URL[] urls2 = set2.getAnnounceURLs(); if (urls2.length == 1) { URL url2 = urls2[0]; String prot2 = url2.getProtocol().toLowerCase(); String host2 = url2.getHost(); if (host1.equals(host2)) { if ((prot1.equals("udp") && prot2.startsWith("http")) || (prot2.equals("udp") && prot1.startsWith("http"))) { list.remove(i); new_sets.add(new TOTorrentAnnounceURLSet[] {set1, set2}); done = true; } } } } } if (!done) { new_sets.add(new TOTorrentAnnounceURLSet[] {set1}); } } } // work out the difference Iterator<TOTorrentAnnounceURLSet[]> ns_it = new_sets.iterator(); // need to copy list as we modify it and returned list ain't thread safe List<TRTrackerAnnouncerHelper> existing_announcers = new ArrayList<TRTrackerAnnouncerHelper>(announcers.getList()); List<TRTrackerAnnouncerHelper> new_announcers = new ArrayList<TRTrackerAnnouncerHelper>(); // first look for unchanged sets while (ns_it.hasNext()) { TOTorrentAnnounceURLSet[] ns = ns_it.next(); Iterator<TRTrackerAnnouncerHelper> a_it = existing_announcers.iterator(); while (a_it.hasNext()) { TRTrackerAnnouncerHelper a = a_it.next(); TOTorrentAnnounceURLSet[] os = a.getAnnounceSets(); if (same(ns, os)) { ns_it.remove(); a_it.remove(); new_announcers.add(a); break; } } } // reuse existing announcers // first remove dht ones from the equation TRTrackerAnnouncerHelper existing_dht_announcer = null; TOTorrentAnnounceURLSet[] new_dht_set = null; ns_it = new_sets.iterator(); while (ns_it.hasNext()) { TOTorrentAnnounceURLSet[] x = ns_it.next(); if (TorrentUtils.isDecentralised(x[0].getAnnounceURLs()[0])) { new_dht_set = x; ns_it.remove(); break; } } Iterator<TRTrackerAnnouncerHelper> an_it = existing_announcers.iterator(); while (an_it.hasNext()) { TRTrackerAnnouncerHelper a = an_it.next(); TOTorrentAnnounceURLSet[] x = a.getAnnounceSets(); if (TorrentUtils.isDecentralised(x[0].getAnnounceURLs()[0])) { existing_dht_announcer = a; an_it.remove(); break; } } if (existing_dht_announcer != null && new_dht_set != null) { new_announcers.add(existing_dht_announcer); } else if (existing_dht_announcer != null) { activated.remove(existing_dht_announcer); existing_dht_announcer.destroy(); } else if (new_dht_set != null) { TRTrackerAnnouncerHelper a = create(torrent, networks, new_dht_set); new_announcers.add(a); } // now do the non-dht ones ns_it = new_sets.iterator(); while (ns_it.hasNext() && existing_announcers.size() > 0) { TRTrackerAnnouncerHelper a = existing_announcers.remove(0); TOTorrentAnnounceURLSet[] s = ns_it.next(); ns_it.remove(); if (activated.contains(a) && torrent.getPrivate() && a instanceof TRTrackerBTAnnouncerImpl) { URL url = a.getTrackerURL(); if (url != null) { forceStop((TRTrackerBTAnnouncerImpl) a, networks, url); } } a.setAnnounceSets(s, networks); new_announcers.add(a); } // create any new ones required ns_it = new_sets.iterator(); while (ns_it.hasNext()) { TOTorrentAnnounceURLSet[] s = ns_it.next(); TRTrackerAnnouncerHelper a = create(torrent, networks, s); new_announcers.add(a); } // finally fix up the announcer list to represent the new state Iterator<TRTrackerAnnouncerHelper> a_it = announcers.iterator(); while (a_it.hasNext()) { TRTrackerAnnouncerHelper a = a_it.next(); if (!new_announcers.contains(a)) { a_it.remove(); try { if (activated.contains(a) && torrent.getPrivate() && a instanceof TRTrackerBTAnnouncerImpl) { URL url = a.getTrackerURL(); if (url != null) { forceStop((TRTrackerBTAnnouncerImpl) a, networks, url); } } } finally { if (Logger.isEnabled()) { Logger.log( new LogEvent( getTorrent(), LOGID, "Deactivating " + getString(a.getAnnounceSets()))); } activated.remove(a); a.destroy(); } } } a_it = new_announcers.iterator(); while (a_it.hasNext()) { TRTrackerAnnouncerHelper a = a_it.next(); if (!announcers.contains(a)) { announcers.add(a); } } if (!is_manual && announcers.size() > 0) { if (activated.size() == 0) { TRTrackerAnnouncerHelper a = announcers.get(0); if (Logger.isEnabled()) { Logger.log( new LogEvent(getTorrent(), LOGID, "Activating " + getString(a.getAnnounceSets()))); } activated.add(a); last_activation_time = SystemTime.getMonotonousTime(); if (provider != null) { to_activate = a; } } setupActivationCheck(ACT_CHECK_INIT_DELAY); } } if (to_activate != null) { if (complete) { to_activate.complete(true); } else { to_activate.update(false); } } }