use of com.biglybt.plugin.dht.DHTPluginContact in project BiglyBT by BiglySoftware.
the class DHTTrackerPlugin method processNonRegistrations.
protected void processNonRegistrations() {
Download ready_download = null;
long ready_download_next_check = -1;
long now = plugin_interface.getUtilities().getCurrentSystemTime();
// unfortunately getting scrape results can acquire locks and there is a vague
// possibility of deadlock here, so pre-fetch the scrape results
List<Download> to_scrape = new ArrayList<>();
try {
this_mon.enter();
Iterator<Download> it = interesting_downloads.keySet().iterator();
while (it.hasNext() && ready_download == null) {
Download download = it.next();
Torrent torrent = download.getTorrent();
if (torrent == null) {
continue;
}
int[] run_data = running_downloads.get(download);
if (run_data == null || run_data[0] == REG_TYPE_DERIVED) {
// looks like we'll need the scrape below
to_scrape.add(download);
}
}
} finally {
this_mon.exit();
}
Map<Download, DownloadScrapeResult> scrapes = new HashMap<>();
for (int i = 0; i < to_scrape.size(); i++) {
Download download = (Download) to_scrape.get(i);
scrapes.put(download, download.getLastScrapeResult());
}
try {
this_mon.enter();
Iterator<Download> it = interesting_downloads.keySet().iterator();
while (it.hasNext() && ready_download == null) {
Download download = it.next();
Torrent torrent = download.getTorrent();
if (torrent == null) {
continue;
}
int[] run_data = running_downloads.get(download);
if (run_data == null || run_data[0] == REG_TYPE_DERIVED) {
boolean force = torrent.wasCreatedByUs();
if (!force) {
if (interesting_pub_max > 0 && interesting_published > interesting_pub_max) {
continue;
}
DownloadScrapeResult scrape = (DownloadScrapeResult) scrapes.get(download);
if (scrape == null) {
continue;
}
if (scrape.getSeedCount() + scrape.getNonSeedCount() > NUM_WANT) {
continue;
}
}
long target = ((Long) interesting_downloads.get(download)).longValue();
long check_period = TorrentUtils.isDecentralised(torrent.getAnnounceURL()) ? INTERESTING_DHT_CHECK_PERIOD : INTERESTING_CHECK_PERIOD;
if (target <= now) {
ready_download = download;
ready_download_next_check = now + check_period;
interesting_downloads.put(download, new Long(ready_download_next_check));
} else if (target - now > check_period) {
interesting_downloads.put(download, new Long(now + (target % check_period)));
}
}
}
} finally {
this_mon.exit();
}
if (ready_download != null) {
final Download f_ready_download = ready_download;
final Torrent torrent = ready_download.getTorrent();
if (ready_download.getFlag(Download.FLAG_METADATA_DOWNLOAD)) {
try {
this_mon.enter();
interesting_downloads.remove(f_ready_download);
} finally {
this_mon.exit();
}
} else if (dht.isDiversified(torrent.getHash())) {
try {
this_mon.enter();
interesting_downloads.remove(f_ready_download);
} finally {
this_mon.exit();
}
} else {
// System.out.println( "presence query for " + ready_download.getName());
final long start = now;
final long f_next_check = ready_download_next_check;
dht.get(torrent.getHash(), "Presence query for '" + ready_download.getName() + "'", (byte) 0, INTERESTING_AVAIL_MAX, ANNOUNCE_TIMEOUT, false, false, new DHTPluginOperationListener() {
private boolean diversified;
private int leechers = 0;
private int seeds = 0;
private int i2p_leechers = 0;
private int i2p_seeds = 0;
@Override
public boolean diversified() {
diversified = true;
return (false);
}
@Override
public void starts(byte[] key) {
}
@Override
public void valueRead(DHTPluginContact originator, DHTPluginValue value) {
boolean is_leecher = (value.getFlags() & DHTPlugin.FLAG_DOWNLOADING) == 1;
if (is_leecher) {
leechers++;
} else {
seeds++;
}
try {
String[] tokens = new String(value.getValue()).split(";");
for (int i = 1; i < tokens.length; i++) {
String token = tokens[i].trim();
if (token.length() > 0) {
if (!Character.isDigit(token.charAt(0))) {
String flag_str = token;
if (flag_str.contains("I")) {
if (is_leecher) {
i2p_leechers++;
} else {
i2p_seeds++;
}
}
}
}
}
} catch (Throwable e) {
}
}
@Override
public void valueWritten(DHTPluginContact target, DHTPluginValue value) {
}
@Override
public void complete(byte[] key, boolean timeout_occurred) {
// System.out.println( " presence query for " + f_ready_download.getName() + "->" + total + "/div = " + diversified );
int total = leechers + seeds;
log(torrent, "Presence query: availability=" + (total == INTERESTING_AVAIL_MAX ? (INTERESTING_AVAIL_MAX + "+") : (total + "")) + ",div=" + diversified + " (elapsed=" + TimeFormatter.formatColonMillis(SystemTime.getCurrentTime() - start) + ")");
if (diversified) {
try {
this_mon.enter();
interesting_downloads.remove(f_ready_download);
} finally {
this_mon.exit();
}
} else if (total < INTERESTING_AVAIL_MAX) {
try {
this_mon.enter();
interesting_downloads.remove(f_ready_download);
} finally {
this_mon.exit();
}
interesting_published++;
if (!disable_put) {
dht.put(torrent.getHash(), "Presence store '" + f_ready_download.getName() + "'", // port 0, no connections
"0".getBytes(), (byte) 0, new DHTPluginOperationListener() {
@Override
public boolean diversified() {
return (true);
}
@Override
public void starts(byte[] key) {
}
@Override
public void valueRead(DHTPluginContact originator, DHTPluginValue value) {
}
@Override
public void valueWritten(DHTPluginContact target, DHTPluginValue value) {
}
@Override
public void complete(byte[] key, boolean timeout_occurred) {
}
});
}
}
try {
this_mon.enter();
int[] run_data = running_downloads.get(f_ready_download);
if (run_data == null) {
run_data = run_data_cache.get(f_ready_download);
}
if (run_data != null) {
if (total < INTERESTING_AVAIL_MAX) {
run_data[1] = seeds;
run_data[2] = leechers;
run_data[3] = total;
} else {
run_data[1] = Math.max(run_data[1], seeds);
run_data[2] = Math.max(run_data[2], leechers);
}
run_data[4] = (int) (SystemTime.getCurrentTime() / 1000);
}
} finally {
this_mon.exit();
}
if (i2p_seeds + i2p_leechers > 0) {
int[] details = (int[]) f_ready_download.getUserData(DOWNLOAD_USER_DATA_I2P_SCRAPE_KEY);
if (details == null) {
details = new int[] { i2p_seeds, i2p_leechers };
f_ready_download.setUserData(DOWNLOAD_USER_DATA_I2P_SCRAPE_KEY, details);
} else {
details[0] = Math.max(details[0], i2p_seeds);
details[1] = Math.max(details[1], i2p_leechers);
}
}
f_ready_download.setScrapeResult(new DownloadScrapeResult() {
@Override
public Download getDownload() {
return (null);
}
@Override
public int getResponseType() {
return (DownloadScrapeResult.RT_SUCCESS);
}
@Override
public int getSeedCount() {
return (seeds);
}
@Override
public int getNonSeedCount() {
return (leechers);
}
@Override
public long getScrapeStartTime() {
return (SystemTime.getCurrentTime());
}
@Override
public void setNextScrapeStartTime(long nextScrapeStartTime) {
}
@Override
public long getNextScrapeStartTime() {
return (f_next_check);
}
@Override
public String getStatus() {
return ("OK");
}
@Override
public URL getURL() {
URL url_to_report = torrent.isDecentralised() ? torrent.getAnnounceURL() : DEFAULT_URL;
return (url_to_report);
}
});
}
});
}
}
}
use of com.biglybt.plugin.dht.DHTPluginContact in project BiglyBT by BiglySoftware.
the class DHTTrackerPlugin method trackerRemove.
protected void trackerRemove(final Download download, final trackerTarget target) {
if (disable_put) {
return;
}
if (download.getFlag(Download.FLAG_METADATA_DOWNLOAD)) {
return;
}
final long start = SystemTime.getCurrentTime();
if (dht.hasLocalKey(target.getHash())) {
increaseActive(download);
dht.remove(target.getHash(), "Tracker dereg of '" + download.getName() + "'" + target.getDesc(), new DHTPluginOperationListener() {
@Override
public boolean diversified() {
return (true);
}
@Override
public void starts(byte[] key) {
}
@Override
public void valueRead(DHTPluginContact originator, DHTPluginValue value) {
}
@Override
public void valueWritten(DHTPluginContact target, DHTPluginValue value) {
}
@Override
public void complete(byte[] key, boolean timeout_occurred) {
if (target.getType() == REG_TYPE_FULL) {
log(download, "Unregistration of '" + target.getDesc() + "' completed (elapsed=" + TimeFormatter.formatColonMillis(SystemTime.getCurrentTime() - start) + ")");
}
decreaseActive(download);
}
});
}
}
use of com.biglybt.plugin.dht.DHTPluginContact in project BiglyBT by BiglySoftware.
the class DHTTrackerPlugin method scrape.
/**
* This is used by the dhtscraper plugin
*/
public DownloadScrapeResult scrape(byte[] hash) {
final int[] seeds = { 0 };
final int[] leechers = { 0 };
final AESemaphore sem = new AESemaphore("DHTTrackerPlugin:scrape");
dht.get(hash, "Scrape for " + ByteFormatter.encodeString(hash).substring(0, 16), DHTPlugin.FLAG_DOWNLOADING, NUM_WANT, SCRAPE_TIMEOUT, false, false, new DHTPluginOperationListener() {
@Override
public boolean diversified() {
return (true);
}
@Override
public void starts(byte[] key) {
}
@Override
public void valueRead(DHTPluginContact originator, DHTPluginValue value) {
if ((value.getFlags() & DHTPlugin.FLAG_DOWNLOADING) == 1) {
leechers[0]++;
} else {
seeds[0]++;
}
}
@Override
public void valueWritten(DHTPluginContact target, DHTPluginValue value) {
}
@Override
public void complete(byte[] key, boolean timeout_occurred) {
sem.release();
}
});
sem.reserve();
return (new DownloadScrapeResult() {
@Override
public Download getDownload() {
return (null);
}
@Override
public int getResponseType() {
return (DownloadScrapeResult.RT_SUCCESS);
}
@Override
public int getSeedCount() {
return (seeds[0]);
}
@Override
public int getNonSeedCount() {
return (leechers[0]);
}
@Override
public long getScrapeStartTime() {
return (0);
}
@Override
public void setNextScrapeStartTime(long nextScrapeStartTime) {
}
@Override
public long getNextScrapeStartTime() {
return (0);
}
@Override
public String getStatus() {
return ("OK");
}
@Override
public URL getURL() {
return (null);
}
});
}
use of com.biglybt.plugin.dht.DHTPluginContact in project BiglyBT by BiglySoftware.
the class DHTTrackerPlugin method trackerPut.
protected void trackerPut(final Download download, RegistrationDetails details) {
final long start = SystemTime.getCurrentTime();
trackerTarget[] targets = details.getTargets(true);
byte flags = details.getFlags();
for (int i = 0; i < targets.length; i++) {
final trackerTarget target = targets[i];
int target_type = target.getType();
// don't let a put block an announce as we don't want to be waiting for
// this at start of day to get a torrent running
// increaseActive( dl );
String encoded = details.getPutDetails().getEncoded();
byte[] encoded_bytes = encoded.getBytes();
DHTPluginValue existing = dht.getLocalValue(target.getHash());
if (existing != null && existing.getFlags() == flags && Arrays.equals(existing.getValue(), encoded_bytes)) {
continue;
}
if (disable_put) {
if (target_type == REG_TYPE_FULL) {
log(download, "Registration of '" + target.getDesc() + "' skipped as disabled due to use of SOCKS proxy");
}
} else if (download.getFlag(Download.FLAG_METADATA_DOWNLOAD)) {
log(download, "Registration of '" + target.getDesc() + "' skipped as metadata download");
} else if (target_type == REG_TYPE_DERIVED && dht.isSleeping()) {
log(download, "Registration of '" + target.getDesc() + "' skipped as sleeping");
} else {
dht.put(target.getHash(), "Tracker reg of '" + download.getName() + "'" + target.getDesc() + " -> " + encoded, encoded_bytes, flags, false, new DHTPluginOperationListener() {
@Override
public boolean diversified() {
return (true);
}
@Override
public void starts(byte[] key) {
}
@Override
public void valueRead(DHTPluginContact originator, DHTPluginValue value) {
}
@Override
public void valueWritten(DHTPluginContact target, DHTPluginValue value) {
}
@Override
public void complete(byte[] key, boolean timeout_occurred) {
if (target.getType() == REG_TYPE_FULL) {
log(download, "Registration of '" + target.getDesc() + "' completed (elapsed=" + TimeFormatter.formatColonMillis((SystemTime.getCurrentTime() - start)) + ")");
}
// decreaseActive( dl );
}
});
}
}
}
use of com.biglybt.plugin.dht.DHTPluginContact in project BiglyBT by BiglySoftware.
the class RelatedContentSearcher method searchRCM.
protected SearchInstance searchRCM(Map<String, Object> search_parameters, SearchObserver _observer) throws SearchException {
final String term = fixupTerm((String) search_parameters.get(SearchProvider.SP_SEARCH_TERM));
final boolean is_popular = isPopularity(term);
final int min_seeds = MapUtils.importInt(search_parameters, SearchProvider.SP_MIN_SEEDS, is_popular ? SEARCH_POP_MIN_SEEDS_DEFAULT : SEARCH_MIN_SEEDS_DEFAULT);
final int min_leechers = MapUtils.importInt(search_parameters, SearchProvider.SP_MIN_LEECHERS, is_popular ? SEARCH_POP_MIN_LEECHERS_DEFAULT : SEARCH_MIN_LEECHERS_DEFAULT);
final MySearchObserver observer = new MySearchObserver(_observer, min_seeds, min_leechers);
final SearchInstance si = new SearchInstance() {
@Override
public void cancel() {
Debug.out("Cancelled");
}
};
if (term == null) {
observer.complete();
} else {
new AEThread2("RCM:search", true) {
@Override
public void run() {
boolean search_cvs_only = SEARCH_CVS_ONLY_DEFAULT;
final Set<String> hashes_sync_me = new HashSet<>();
try {
List<RelatedContent> matches = matchContent(term, min_seeds, min_leechers, true, search_cvs_only);
for (final RelatedContent c : matches) {
final byte[] hash = c.getHash();
if (hash == null) {
continue;
}
hashes_sync_me.add(Base32.encode(hash));
SearchResult result = new SearchResult() {
@Override
public Object getProperty(int property_name) {
if (property_name == SearchResult.PR_VERSION) {
return (new Long(c.getVersion()));
} else if (property_name == SearchResult.PR_NAME) {
return (c.getTitle());
} else if (property_name == SearchResult.PR_SIZE) {
return (c.getSize());
} else if (property_name == SearchResult.PR_HASH) {
return (hash);
} else if (property_name == SearchResult.PR_RANK) {
return (new Long(c.getRank() / 4));
} else if (property_name == SearchResult.PR_SEED_COUNT) {
return (new Long(c.getSeeds()));
} else if (property_name == SearchResult.PR_LEECHER_COUNT) {
return (new Long(c.getLeechers()));
} else if (property_name == SearchResult.PR_SUPER_SEED_COUNT) {
return (new Long(0));
} else if (property_name == SearchResult.PR_PUB_DATE) {
long date = c.getPublishDate();
if (date <= 0) {
return (null);
}
return (new Date(date));
} else if (property_name == SearchResult.PR_TORRENT_LINK || property_name == SearchResult.PR_DOWNLOAD_LINK || property_name == SearchResult.PR_DOWNLOAD_BUTTON_LINK) {
byte[] hash = c.getHash();
if (hash != null) {
return (UrlUtils.getMagnetURI(hash, c.getTitle(), c.getNetworks()));
}
} else if (property_name == SearchResult.PR_CATEGORY) {
String[] tags = c.getTags();
if (tags != null) {
for (String tag : tags) {
if (!tag.startsWith("_")) {
return (tag);
}
}
}
} else if (property_name == RelatedContentManager.RCM_SEARCH_PROPERTY_TRACKER_KEYS) {
return (c.getTrackerKeys());
} else if (property_name == RelatedContentManager.RCM_SEARCH_PROPERTY_WEB_SEED_KEYS) {
return (c.getWebSeedKeys());
} else if (property_name == RelatedContentManager.RCM_SEARCH_PROPERTY_TAGS) {
return (c.getTags());
} else if (property_name == RelatedContentManager.RCM_SEARCH_PROPERTY_NETWORKS) {
return (c.getNetworks());
}
return (null);
}
};
observer.resultReceived(si, result);
}
} finally {
try {
final List<DistributedDatabaseContact> initial_hinted_contacts = searchForeignBlooms(term);
final Set<DistributedDatabaseContact> extra_hinted_contacts = new HashSet<>();
Collections.shuffle(initial_hinted_contacts);
// test injection of local
// hinted_contacts.add( 0, ddb.getLocalContact());
final LinkedList<DistributedDatabaseContact> contacts_to_search = new LinkedList<>();
final Map<InetSocketAddress, DistributedDatabaseContact> contact_map = new HashMap<>();
for (DistributedDatabaseContact c : initial_hinted_contacts) {
// stick in map so non-hinted get removed below, but interleave later
contact_map.put(c.getAddress(), c);
}
if (ddb != null) {
DHTInterface[] dhts = dht_plugin.getDHTInterfaces();
boolean public_dht = dht_plugin.getNetwork() == AENetworkClassifier.AT_PUBLIC;
for (DHTInterface dht : dhts) {
if (dht.isIPV6()) {
continue;
}
int network = dht.getNetwork();
if (public_dht && search_cvs_only && network != DHT.NW_AZ_CVS) {
logSearch("Search: ignoring main DHT");
continue;
}
DHTPluginContact[] contacts = dht.getReachableContacts();
Collections.shuffle(Arrays.asList(contacts));
for (DHTPluginContact dc : contacts) {
InetSocketAddress address = dc.getAddress();
if (!contact_map.containsKey(address)) {
try {
DistributedDatabaseContact c = importContact(dc, network);
contact_map.put(address, c);
contacts_to_search.add(c);
} catch (Throwable e) {
}
}
}
}
if (contact_map.size() < MAX_REMOTE_SEARCH_CONTACTS) {
for (DHTInterface dht : dhts) {
if (dht.isIPV6()) {
continue;
}
int network = dht.getNetwork();
if (public_dht && search_cvs_only && network != DHT.NW_AZ_CVS) {
logSearch("Search: ignoring main DHT");
continue;
}
DHTPluginContact[] contacts = dht.getRecentContacts();
for (DHTPluginContact dc : contacts) {
InetSocketAddress address = dc.getAddress();
if (!contact_map.containsKey(address)) {
try {
DistributedDatabaseContact c = importContact(dc, network);
contact_map.put(address, c);
contacts_to_search.add(c);
if (contact_map.size() >= MAX_REMOTE_SEARCH_CONTACTS) {
break;
}
} catch (Throwable e) {
}
}
}
if (contact_map.size() >= MAX_REMOTE_SEARCH_CONTACTS) {
break;
}
}
}
}
// interleave hinted ones so we get some variety
int desired_pos = 0;
for (DistributedDatabaseContact dc : initial_hinted_contacts) {
if (desired_pos < contacts_to_search.size()) {
contacts_to_search.add(desired_pos, dc);
desired_pos += 2;
} else {
contacts_to_search.addLast(dc);
}
}
long start = SystemTime.getMonotonousTime();
long max = MAX_REMOTE_SEARCH_MILLIS;
final AESemaphore sem = new AESemaphore("RCM:rems");
int sent = 0;
final int[] done = { 0 };
logSearch("Search starts: contacts=" + contacts_to_search.size() + ", hinted=" + initial_hinted_contacts.size());
while (true) {
if (observer.getResultCount() >= 200 || SystemTime.getMonotonousTime() - start >= max) {
logSearch("Hard limit exceeded");
return;
}
if (sent >= MAX_REMOTE_SEARCH_CONTACTS) {
logSearch("Max contacts searched");
break;
}
final DistributedDatabaseContact contact_to_search;
synchronized (contacts_to_search) {
if (contacts_to_search.isEmpty()) {
logSearch("Contacts exhausted");
break;
} else {
contact_to_search = contacts_to_search.removeFirst();
}
}
new AEThread2("RCM:rems", true) {
@Override
public void run() {
try {
logSearch("Searching " + contact_to_search.getAddress());
List<DistributedDatabaseContact> extra_contacts = sendRemoteSearch(si, hashes_sync_me, contact_to_search, term, min_seeds, min_leechers, observer);
if (extra_contacts == null) {
logSearch(" " + contact_to_search.getAddress() + " failed");
foreignBloomFailed(contact_to_search);
} else {
String type;
if (initial_hinted_contacts.contains(contact_to_search)) {
type = "i";
} else if (extra_hinted_contacts.contains(contact_to_search)) {
type = "e";
} else {
type = "n";
}
logSearch(" " + contact_to_search.getAddress() + " OK " + type + " - additional=" + extra_contacts.size());
synchronized (contacts_to_search) {
int insert_point = 0;
if (type.equals("i")) {
for (int i = 0; i < contacts_to_search.size(); i++) {
if (extra_hinted_contacts.contains(contacts_to_search.get(i))) {
insert_point = i + 1;
}
}
}
for (DistributedDatabaseContact c : extra_contacts) {
InetSocketAddress address = c.getAddress();
if (!contact_map.containsKey(address)) {
logSearch(" additional target: " + address);
extra_hinted_contacts.add(c);
contact_map.put(address, c);
contacts_to_search.add(insert_point, c);
}
}
}
}
} finally {
synchronized (done) {
done[0]++;
}
sem.release();
}
}
}.start();
sent++;
synchronized (done) {
if (done[0] >= MAX_REMOTE_SEARCH_CONTACTS / 2) {
logSearch("Switching to reduced time limit (1)");
// give another 5 secs for results to come in
start = SystemTime.getMonotonousTime();
max = REDUCED_REMOTE_SEARCH_MILLIS;
break;
}
}
if (sent > 10) {
try {
Thread.sleep(250);
} catch (Throwable e) {
}
}
}
logSearch("Request dispatch complete: sent=" + sent + ", done=" + done[0]);
for (int i = 0; i < sent; i++) {
if (done[0] > sent * 9 / 10) {
logSearch("9/10ths replied (" + done[0] + "/" + sent + "), done");
break;
}
long remaining = (start + max) - SystemTime.getMonotonousTime();
if (remaining > REDUCED_REMOTE_SEARCH_MILLIS && done[0] >= MAX_REMOTE_SEARCH_CONTACTS / 2) {
logSearch("Switching to reduced time limit (2)");
// give another 5 secs for results to come in
start = SystemTime.getMonotonousTime();
max = REDUCED_REMOTE_SEARCH_MILLIS;
}
if (remaining > 0) {
sem.reserve(250);
} else {
logSearch("Time exhausted");
break;
}
}
} finally {
logSearch("Search complete");
observer.complete();
}
}
}
}.start();
}
return (si);
}
Aggregations