use of com.biglybt.core.logging.LogEvent in project BiglyBT by BiglySoftware.
the class TRTrackerBTAnnouncerImpl method constructUrl.
public URL constructUrl(String evt, URL _url) throws Exception {
String url = _url.toString();
StringBuffer request = new StringBuffer(url);
// if url already has a query component then just append our parameters on the end
if (url.indexOf('?') != -1) {
request.append('&');
} else {
request.append('?');
}
// the client-id stuff RELIES on info_hash being the FIRST parameter added by
// us to the URL, so don't change it!
request.append(info_hash);
request.append(tracker_peer_id_str);
String port_details = announce_data_provider.getCryptoLevel() == NetworkManager.CRYPTO_OVERRIDE_REQUIRED ? TRTrackerUtils.getPortsForURLFullCrypto() : TRTrackerUtils.getPortsForURL();
request.append(port_details);
request.append("&uploaded=").append(announce_data_provider.getTotalSent());
request.append("&downloaded=").append(announce_data_provider.getTotalReceived());
if (Constants.DOWNLOAD_SOURCES_PRETEND_COMPLETE) {
request.append("&left=0");
} else {
request.append("&left=").append(announce_data_provider.getRemaining());
}
// 3017: added at request of tracker admins who want to be able to monitor swarm poisoning
request.append("&corrupt=").append(announce_data_provider.getFailedHashCheck());
// TrackerID extension
if (tracker_id.length() > 0) {
request.append("&trackerid=").append(tracker_id);
}
if (evt.length() != 0) {
request.append("&event=").append(evt);
}
boolean stopped = evt.equals("stopped");
if (stopped) {
request.append("&numwant=0");
if (stopped_for_queue) {
request.append("&azq=1");
}
} else {
// calculate how many peers we should ask for
int numwant = Math.min(calculateNumWant(), userMaxNumwant);
request.append("&numwant=").append(numwant);
// no_peer_id has been made obsolete by 'compact'
}
// actually, leave this in, ask PARG why!
request.append("&no_peer_id=1");
String tracker_network = AENetworkClassifier.categoriseAddress(_url.getHost());
// latest space saving measure, a compact return type where peers are returned
// as 6 byte entries in a single byte[] (4 bytes ip, 2 byte port)
// leave this as always supplied, ask PARG why
request.append("&compact=1");
// any explicit override takes precedence over any implicit override added
// when hosting torrents
String explicit_ips = COConfigurationManager.getStringParameter("Override Ip", "");
String ip = null;
// make sure this tracker network is enabled
boolean network_ok = false;
boolean normal_network_ok = false;
if (peer_networks == null) {
network_ok = true;
normal_network_ok = true;
} else {
for (int i = 0; i < peer_networks.length; i++) {
if (peer_networks[i] == AENetworkClassifier.AT_PUBLIC) {
normal_network_ok = true;
}
if (peer_networks[i] == tracker_network) {
network_ok = true;
}
}
}
if (!network_ok) {
throw (new Exception("Network not enabled for url '" + _url + "'"));
}
String normal_explicit = null;
if (explicit_ips.length() > 0) {
// gotta select an appropriate override based on network type
StringTokenizer tok = new StringTokenizer(explicit_ips, ";");
while (tok.hasMoreTokens()) {
String this_address = tok.nextToken().trim();
if (this_address.length() > 0) {
String cat = AENetworkClassifier.categoriseAddress(this_address);
if (cat == AENetworkClassifier.AT_PUBLIC) {
normal_explicit = this_address;
}
if (tracker_network == cat) {
ip = this_address;
break;
}
}
}
}
if (ip == null) {
if (normal_network_ok && normal_explicit != null) {
ip = normal_explicit;
} else {
if (ip_override != null && !TorrentUtils.isDecentralised(ip_override)) {
ip = ip_override;
}
}
}
if (ip != null) {
if (tracker_network == AENetworkClassifier.AT_PUBLIC) {
try {
ip = PRHelpers.DNSToIPAddress(ip);
} catch (UnknownHostException e) {
if (Logger.isEnabled())
Logger.log(new LogEvent(torrent, LOGID, LogEvent.LT_ERROR, "IP Override host resolution of '" + ip + "' fails, using unresolved address"));
}
}
request.append("&ip=").append(ip);
}
if (COConfigurationManager.getBooleanParameter("Tracker Key Enable Client", true)) {
request.append("&key=").append(helper.getTrackerKey());
}
String ext = announce_data_provider.getExtensions();
if (ext != null) {
while (ext.startsWith("&")) {
ext = ext.substring(1);
}
request.append("&");
request.append(ext);
}
request.append("&azver=" + TRTrackerAnnouncer.AZ_TRACKER_VERSION_CURRENT);
if (az_tracker && !stopped) {
int up = announce_data_provider.getUploadSpeedKBSec(evt.equals("started"));
if (up > 0) {
request.append("&azup=").append(up);
}
String as = NetworkAdmin.getSingleton().getCurrentASN().getAS();
if (as.length() > 0) {
request.append("&azas=").append(URLEncoder.encode(as, "UTF8"));
}
DHTNetworkPosition best_position = DHTNetworkPositionManager.getBestLocalPosition();
if (best_position != null) {
try {
byte[] bytes = DHTNetworkPositionManager.serialisePosition(best_position);
request.append("&aznp=").append(Base32.encode(bytes));
} catch (Throwable e) {
Debug.printStackTrace(e);
}
}
}
if (tracker_network == AENetworkClassifier.AT_I2P) {
String temp = request.toString();
int pos = temp.indexOf('?');
String head = temp.substring(0, pos);
String tail = temp.substring(pos + 1);
String[] bits = tail.split("&");
Map<String, String> map = new HashMap<>();
for (String bit : bits) {
String[] arg = bit.split("=");
map.put(arg[0], arg[1]);
}
tail = "";
for (String str : new String[] { "info_hash", "peer_id", "port", "ip", "uploaded", "downloaded", "left", "compact", "event", "numwant" }) {
String val = map.get(str);
if (val != null) {
tail += (tail.length() == 0 ? "" : "&") + str + "=" + map.get(str);
}
}
request = new StringBuffer(head + "?" + tail);
}
return new URL(request.toString());
}
use of com.biglybt.core.logging.LogEvent in project BiglyBT by BiglySoftware.
the class TRTrackerBTAnnouncerImpl method announceHTTPSupport.
private String announceHTTPSupport(// overwritten if redirected
URL[] tracker_url, URL original_reqUrl, Proxy proxy, boolean first_effort, ByteArrayOutputStream message) throws IOException {
TRTrackerUtils.checkForBlacklistedURLs(original_reqUrl);
URL reqUrl = TRTrackerUtils.adjustURLForHosting(original_reqUrl);
reqUrl = AddressUtils.adjustURL(reqUrl);
if (reqUrl != original_reqUrl) {
if (Logger.isEnabled()) {
Logger.log(new LogEvent(torrent, LOGID, " HTTP: url adjusted to " + reqUrl));
}
}
String failure_reason = null;
HttpURLConnection con;
Properties http_properties = new Properties();
http_properties.put(ClientIDGenerator.PR_URL, reqUrl);
if (proxy != null) {
http_properties.put(ClientIDGenerator.PR_PROXY, proxy);
}
if (enable_sni_hack) {
http_properties.put(ClientIDGenerator.PR_SNI_HACK, true);
}
try {
ClientIDManagerImpl.getSingleton().generateHTTPProperties(torrent_hash.getBytes(), http_properties);
} catch (ClientIDException e) {
throw (new IOException(e.getMessage()));
}
reqUrl = (URL) http_properties.get(ClientIDGenerator.PR_URL);
boolean is_https = reqUrl.getProtocol().equalsIgnoreCase("https");
if (is_https) {
// see ConfigurationChecker for SSL client defaults
HttpsURLConnection ssl_con;
if (proxy == null) {
ssl_con = (HttpsURLConnection) reqUrl.openConnection();
} else {
ssl_con = (HttpsURLConnection) reqUrl.openConnection(proxy);
}
if (!internal_error_hack) {
ssl_con.setHostnameVerifier(new HostnameVerifier() {
@Override
public boolean verify(String host, SSLSession session) {
return (true);
}
});
}
if (dh_hack) {
UrlUtils.DHHackIt(ssl_con);
}
if (!first_effort) {
// meh, some https trackers are just screwed
TrustManager[] trustAllCerts = SESecurityManager.getAllTrustingTrustManager();
try {
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, trustAllCerts, RandomUtils.SECURE_RANDOM);
SSLSocketFactory factory = sc.getSocketFactory();
ssl_con.setSSLSocketFactory(factory);
} catch (Throwable e) {
}
}
con = ssl_con;
} else {
if (proxy == null) {
con = (HttpURLConnection) reqUrl.openConnection();
} else {
con = (HttpURLConnection) reqUrl.openConnection(proxy);
}
}
// we want this true but some plugins (grrr) set the global default not to follow
// redirects
con.setInstanceFollowRedirects(true);
String user_agent = (String) http_properties.get(ClientIDGenerator.PR_USER_AGENT);
if (user_agent != null) {
con.setRequestProperty("User-Agent", user_agent);
}
con.setRequestProperty("Connection", "close");
// some trackers support gzip encoding of replies
con.addRequestProperty("Accept-Encoding", "gzip");
try {
try {
con.connect();
} catch (AEProxyFactory.UnknownHostException e) {
throw (new UnknownHostException(e.getMessage()));
} catch (IOException e) {
if (is_https) {
String msg = Debug.getNestedExceptionMessage(e);
if (msg.contains("unrecognized_name")) {
// SNI borkage - used to fix by globally disabling SNI but this screws too many other things
enable_sni_hack = true;
} else if (msg.contains("internal_error") || msg.contains("handshake_failure")) {
internal_error_hack = true;
} else if (msg.contains("DH keypair")) {
dh_hack = true;
}
}
throw (e);
}
InputStream is = null;
try {
is = con.getInputStream();
String resulting_url_str = con.getURL().toString();
if (!reqUrl.toString().equals(resulting_url_str)) {
// some kind of redirect has occurred. Unfortunately we can't get at the underlying
// redirection reason (temp, perm etc) so we support the use of an explicit indicator
// in the resulting url
String marker = "permredirect=1";
int pos = resulting_url_str.indexOf(marker);
if (pos != -1) {
// include the '&' or '?'
pos = pos - 1;
try {
URL redirect_url = new URL(resulting_url_str.substring(0, pos));
tracker_url[0] = redirect_url;
} catch (Throwable e) {
Debug.printStackTrace(e);
}
}
}
String encoding = con.getHeaderField("content-encoding");
boolean gzip = encoding != null && encoding.equalsIgnoreCase("gzip");
if (gzip) {
is = new GZIPInputStream(is);
}
// there are some trackers out there that don't set content length correctly
// so we can't reliably use it :(
// con.getContentLength();
int content_length = -1;
// System.out.println(length);
byte[] data = new byte[1024];
int num_read = 0;
while (content_length <= 0 || num_read < content_length) {
try {
int len = is.read(data);
if (len > 0) {
message.write(data, 0, len);
num_read += len;
if (num_read > 128 * 1024) {
// someone's sending us junk, bail out
message.reset();
throw (new Exception("Tracker response invalid (too large)"));
}
} else if (len == 0) {
Thread.sleep(20);
} else {
break;
}
} catch (Exception e) {
if (Logger.isEnabled()) {
Logger.log(new LogEvent(torrent, LOGID, "Exception while Requesting Tracker", e));
Logger.log(new LogEvent(torrent, LOGID, LogEvent.LT_ERROR, "Message Received was : " + message));
}
failure_reason = exceptionToString(e);
break;
}
}
if (Logger.isEnabled())
Logger.log(new LogEvent(torrent, LOGID, "Tracker Announcer [" + lastUsedUrl + "] has received : " + message));
} catch (SSLException e) {
throw (e);
} catch (Exception e) {
// e.printStackTrace();
failure_reason = exceptionToString(e);
} finally {
if (is != null) {
try {
is.close();
} catch (Exception e) {
}
is = null;
}
}
} finally {
con.disconnect();
}
return (failure_reason);
}
use of com.biglybt.core.logging.LogEvent in project BiglyBT by BiglySoftware.
the class TRTrackerBTAnnouncerImpl method updateOld.
private byte[] updateOld(URL[] tracker_url, URL reqUrl) throws Exception {
// set context in case authentication dialog is required
boolean errorLevel = true;
try {
TorrentUtils.setTLSTorrentHash(torrent_hash);
for (int i = 0; i < 2; i++) {
String failure_reason = null;
String protocol = reqUrl.getProtocol();
try {
if (Logger.isEnabled()) {
Logger.log(new LogEvent(torrent, LOGID, "Tracker Announcer is Requesting: " + reqUrl));
}
ByteArrayOutputStream message = new ByteArrayOutputStream();
URL udpAnnounceURL = null;
boolean udp_probe = false;
if (protocol.equalsIgnoreCase("udp")) {
if (udpAnnounceEnabled) {
udpAnnounceURL = reqUrl;
} else {
throw (new IOException("UDP Tracker protocol disabled"));
}
} else if (protocol.equalsIgnoreCase("http") && (!az_tracker) && (!TorrentUtils.isReallyPrivate(torrent)) && announceCount % autoUDPprobeEvery == 0 && udpProbeEnabled && udpAnnounceEnabled) {
if ((stopped || announceCount == 0 || (announceCount < trackerUrlLists.size() && announceFailCount == announceCount)) && !TRTrackerUtils.isUDPProbeOK(reqUrl)) {
// skip probe
} else {
String tracker_network = AENetworkClassifier.categoriseAddress(reqUrl.getHost());
if (tracker_network == AENetworkClassifier.AT_PUBLIC) {
udpAnnounceURL = new URL(reqUrl.toString().replaceFirst("^http", "udp"));
udp_probe = true;
}
}
}
if (udpAnnounceURL != null) {
failure_reason = announceUDP(reqUrl, message, udp_probe);
if ((failure_reason != null || message.size() == 0) && udp_probe) {
// automatic UDP probe failed, use HTTP again
udpAnnounceURL = null;
if (autoUDPprobeEvery < 16) {
autoUDPprobeEvery <<= 1;
} else {
// unregister in case the tracker somehow changed its capabilities
TRTrackerUtils.setUDPProbeResult(reqUrl, false);
}
if (Logger.isEnabled()) {
Logger.log(new LogEvent(torrent, LOGID, LogEvent.LT_INFORMATION, "redirection of http announce [" + tracker_url[0] + "] to udp failed, will retry in " + autoUDPprobeEvery + " announces"));
}
} else if (failure_reason == null && udp_probe) {
TRTrackerUtils.setUDPProbeResult(reqUrl, true);
if (Logger.isEnabled()) {
Logger.log(new LogEvent(torrent, LOGID, LogEvent.LT_INFORMATION, "redirection of http announce [" + tracker_url[0] + "] to udp successful"));
}
autoUDPprobeEvery = 1;
autoUDPProbeSuccessCount++;
}
}
announceCount++;
if (udpAnnounceURL == null) {
boolean failed = false;
if (!az_tracker && !tcpAnnounceEnabled) {
String tracker_network = AENetworkClassifier.categoriseAddress(reqUrl.getHost());
if (tracker_network == AENetworkClassifier.AT_PUBLIC) {
failure_reason = "HTTP Tracker protocol disabled";
failed = true;
}
}
if (!failed) {
failure_reason = announceHTTP(tracker_url, reqUrl, message, i == 0);
}
}
if (message.size() > 0) {
return (message.toByteArray());
}
if (failure_reason == null) {
failure_reason = "No data received from tracker";
if (reqUrl.getProtocol().equalsIgnoreCase("udp")) {
errorLevel = false;
}
}
} catch (SSLException e) {
if (i == 0) {
if (SESecurityManager.installServerCertificates(reqUrl) != null) {
// retry with new certificate
continue;
}
failure_reason = exceptionToString(e);
} else {
failure_reason = exceptionToString(e);
}
} catch (IOException e) {
if (e instanceof UnknownHostException || e instanceof ConnectException) {
errorLevel = false;
}
if (i == 0 && protocol.toLowerCase().startsWith("http")) {
URL retry_url = UrlUtils.getIPV4Fallback(reqUrl);
if (retry_url != null) {
reqUrl = retry_url;
continue;
}
}
failure_reason = exceptionToString(e);
} catch (Exception e) {
// e.printStackTrace();
failure_reason = exceptionToString(e);
}
if (failure_reason != null && failure_reason.contains("401")) {
failure_reason = "Tracker authentication failed";
errorLevel = false;
}
if (Logger.isEnabled())
Logger.log(new LogEvent(torrent, LOGID, errorLevel ? LogEvent.LT_ERROR : LogEvent.LT_WARNING, "Exception while processing the Tracker Request for " + reqUrl + ": " + failure_reason));
throw (new Exception(failure_reason));
}
throw (new Exception("Internal Error: should never get here"));
} finally {
TorrentUtils.setTLSTorrentHash(null);
}
}
use of com.biglybt.core.logging.LogEvent in project BiglyBT by BiglySoftware.
the class TRTrackerBTAnnouncerImpl method decodeTrackerResponse.
protected TRTrackerAnnouncerResponseImpl decodeTrackerResponse(URL url, byte[] data) {
String failure_reason;
if (data == null) {
failure_reason = "no response";
} else {
try {
// parse the metadata
Map metaData = null;
try {
metaData = BDecoder.decode(data);
// obey any peers source restrictions
Object o = metaData.get("az_ps");
if (o instanceof List) {
List peer_sources = (List) o;
List x = new ArrayList();
for (int i = 0; i < peer_sources.size(); i++) {
Object o1 = peer_sources.get(i);
if (o1 instanceof byte[]) {
x.add(new String((byte[]) o1));
}
}
String[] y = new String[x.size()];
x.toArray(y);
announce_data_provider.setPeerSources(y);
}
try {
byte[] b_warning_message = (byte[]) metaData.get("warning message");
if (b_warning_message != null && COConfigurationManager.getBooleanParameter("Tracker Client Show Warnings")) {
String warning_message = new String(b_warning_message);
if (!warning_message.equals(last_tracker_message)) {
last_tracker_message = warning_message;
boolean log_it = false;
try {
class_mon.enter();
String last_warning_message = (String) tracker_report_map.get(url.getHost());
if (last_warning_message == null || !warning_message.equals(last_warning_message)) {
log_it = true;
tracker_report_map.put(url.getHost(), warning_message);
}
} finally {
class_mon.exit();
}
if (log_it) {
Logger.logTextResource(new LogAlert(torrent, 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 {
if (!metaData.containsKey("interval")) {
throw (new Exception("interval missing"));
}
tracker_interval = time_to_wait = ((Long) metaData.get("interval")).longValue();
Long raw_min_interval = (Long) metaData.get("min interval");
if (Logger.isEnabled()) {
Logger.log(new LogEvent(torrent, LOGID, LogEvent.LT_INFORMATION, "Received from announce: 'interval' = " + time_to_wait + "; 'min interval' = " + raw_min_interval));
}
// guard against crazy return values
if (time_to_wait < 0 || time_to_wait > 0xffffffffL) {
time_to_wait = 0xffffffffL;
}
if (raw_min_interval != null) {
tracker_min_interval = min_interval = raw_min_interval.longValue();
// Note: Many trackers set min_interval and interval the same.
if (min_interval < 1) {
if (Logger.isEnabled()) {
Logger.log(new LogEvent(torrent, LOGID, LogEvent.LT_INFORMATION, "Tracker being silly and " + "returning a 'min interval' of less than 1 second (" + min_interval + ")"));
}
min_interval = 0;
} else if (min_interval > time_to_wait) {
if (Logger.isEnabled()) {
Logger.log(new LogEvent(torrent, LOGID, LogEvent.LT_INFORMATION, "Tracker being silly and " + "returning a 'min interval' (" + min_interval + ") greater than recommended announce 'interval'" + " (" + time_to_wait + ")"));
}
min_interval = 0;
}
} else {
// tracker owners complain we announce too much but then never
// implement "min interval". So take it into our own hands
// and enforce a min_interval of interval when there is no
// "min interval"
min_interval = time_to_wait > 30 ? time_to_wait - 10 : time_to_wait;
}
if (userMinInterval != 0) {
time_to_wait = Math.max(userMinInterval, time_to_wait);
min_interval = Math.max(min_interval, userMinInterval);
if (Logger.isEnabled()) {
Logger.log(new LogEvent(torrent, LOGID, LogEvent.LT_INFORMATION, "Overriding with user settings: 'interval' = " + time_to_wait + "; 'min interval' = " + min_interval));
}
}
// mess up the "ignore useless values"
if (time_to_wait > 30) {
time_to_wait -= 10;
}
if (metaData.containsKey("failure reason")) {
throw (new Exception("Tracker reported 'failure reason'"));
}
} 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"));
}
// 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 = getLong(metaData, "incomplete");
Long complete_l = getLong(metaData, "complete");
Long downloaded_l = getLong(metaData, "downloaded");
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);
}
byte[] crypto_flags = (byte[]) metaData.get("crypto_flags");
// build the list of peers
List valid_meta_peers = new ArrayList();
Object meta_peers_peek = metaData.get("peers");
Long az_compact_l = (Long) metaData.get("azcompact");
long az_compact = az_compact_l == null ? 0 : az_compact_l.longValue();
boolean this_is_az_tracker = az_compact == 2;
if (az_tracker != this_is_az_tracker || lastUsedUrl != lastAZTrackerCheckedURL) {
lastAZTrackerCheckedURL = lastUsedUrl;
az_tracker = this_is_az_tracker;
TRTrackerUtils.setAZTracker(url, az_tracker);
}
if (az_compact == 2) {
// latest return to dictionary based data
List meta_peers = (List) meta_peers_peek;
int peers_length = meta_peers.size();
if (Logger.isEnabled()) {
Logger.log(new LogEvent(torrent, LOGID, "ANNOUNCE CompactPeers2: num=" + peers_length));
}
if (peers_length > 1) {
// calculate average rtt to use for those with no rtt
long total_rtt = 0;
int rtt_count = 0;
for (int i = 0; i < peers_length; i++) {
Map peer = (Map) meta_peers.get(i);
Long l_rtt = (Long) peer.get("r");
if (l_rtt != null) {
long rtt = l_rtt.longValue();
if (rtt <= 0) {
// invalid, remove
peer.remove("r");
} else {
total_rtt += rtt;
}
rtt_count++;
}
}
final int average_rtt = (int) (rtt_count == 0 ? 0 : (total_rtt / rtt_count));
// sort into smallest rtt order with biased at front
Collections.sort(meta_peers, new Comparator() {
@Override
public int compare(Object o1, Object o2) {
Map map1 = (Map) o1;
Map map2 = (Map) o2;
Long l_rtt1 = (Long) map1.get("r");
Long l_rtt2 = (Long) map2.get("r");
boolean biased_1 = map1.containsKey("b");
boolean biased_2 = map2.containsKey("b");
if (biased_1 == biased_2) {
int rtt1 = l_rtt1 == null ? average_rtt : l_rtt1.intValue();
int rtt2 = l_rtt2 == null ? average_rtt : l_rtt2.intValue();
return (rtt1 - rtt2);
} else if (biased_1) {
return (-1);
} else {
return (+1);
}
}
});
// interleave non-biased peers with good rtt
int biased_pos = peers_length;
int non_biased_pos = peers_length;
for (int i = 0; i < peers_length; i++) {
Map peer = (Map) meta_peers.get(i);
if (peer.containsKey("b")) {
if (i == 0) {
biased_pos = i;
}
} else {
non_biased_pos = i;
break;
}
}
List new_peers = new ArrayList(peers_length);
int non_biased_start = non_biased_pos;
boolean last_biased = true;
while (biased_pos < non_biased_start || non_biased_pos < peers_length) {
if (biased_pos < non_biased_start) {
if (non_biased_pos < peers_length) {
Map biased = (Map) meta_peers.get(biased_pos);
Map non_biased = (Map) meta_peers.get(non_biased_pos);
boolean use_biased;
if (!last_biased) {
use_biased = true;
} else {
Long l_rtt_biased = (Long) biased.get("r");
Long l_rtt_non_biased = (Long) non_biased.get("r");
int biased_rtt = l_rtt_biased == null ? average_rtt : l_rtt_biased.intValue();
int non_biased_rtt = l_rtt_non_biased == null ? average_rtt : l_rtt_non_biased.intValue();
use_biased = non_biased_rtt >= biased_rtt;
}
if (use_biased) {
new_peers.add(biased);
biased_pos++;
} else {
new_peers.add(non_biased);
non_biased_pos++;
}
last_biased = use_biased;
} else {
new_peers.add(meta_peers.get(biased_pos++));
}
} else {
new_peers.add(meta_peers.get(non_biased_pos++));
}
}
meta_peers = new_peers;
}
for (int i = 0; i < peers_length; i++) {
Map peer = (Map) meta_peers.get(i);
try {
byte[] ip_bytes = (byte[]) peer.get("i");
String ip;
if (ip_bytes.length == 4) {
int ip1 = 0xff & ip_bytes[0];
int ip2 = 0xff & ip_bytes[1];
int ip3 = 0xff & ip_bytes[2];
int ip4 = 0xff & ip_bytes[3];
ip = ip1 + "." + ip2 + "." + ip3 + "." + ip4;
} else {
StringBuilder sb = new StringBuilder(39);
for (int j = 0; j < 16; j += 2) {
sb.append(Integer.toHexString(((ip_bytes[j] << 8) & 0xff00) | (ip_bytes[j + 1] & 0x00ff)));
if (j < 14) {
sb.append(":");
}
}
ip = sb.toString();
}
byte[] tcp_bytes = (byte[]) peer.get("t");
int tcp_port = ((tcp_bytes[0] & 0xff) << 8) + (tcp_bytes[1] & 0xff);
byte[] peer_peer_id = TRTrackerAnnouncerFactoryImpl.getAnonymousPeerId(ip, tcp_port);
int udp_port = 0;
byte[] udp_bytes = (byte[]) peer.get("u");
if (udp_bytes != null) {
if (udp_bytes.length == 0) {
udp_port = tcp_port;
} else {
udp_port = ((udp_bytes[0] & 0xff) << 8) + (udp_bytes[1] & 0xff);
}
}
int http_port = 0;
byte[] http_bytes = (byte[]) peer.get("h");
if (http_bytes != null) {
http_port = ((http_bytes[0] & 0xff) << 8) + (http_bytes[1] & 0xff);
}
short protocol = DownloadAnnounceResultPeer.PROTOCOL_NORMAL;
byte[] protocol_bytes = (byte[]) peer.get("c");
if (protocol_bytes != null) {
protocol = (protocol_bytes[0] & 0x01) == 0 ? DownloadAnnounceResultPeer.PROTOCOL_NORMAL : DownloadAnnounceResultPeer.PROTOCOL_CRYPT;
}
Long l_azver = (Long) peer.get("v");
byte az_ver = l_azver == null ? TRTrackerAnnouncer.AZ_TRACKER_VERSION_1 : l_azver.byteValue();
Long l_up_speed = (Long) peer.get("s");
boolean biased = peer.containsKey("b");
if (biased) {
PeerClassifier.setAzureusIP(ip);
}
TRTrackerAnnouncerResponsePeerImpl new_peer = new TRTrackerAnnouncerResponsePeerImpl(PEPeerSource.PS_BT_TRACKER, peer_peer_id, ip, tcp_port, udp_port, http_port, protocol, az_ver, l_up_speed == null ? 0 : l_up_speed.shortValue());
if (Logger.isEnabled()) {
String extra = "";
Long l_rtt = (Long) peer.get("r");
if (l_rtt != null) {
extra = ",rtt=" + l_rtt;
}
if (biased) {
extra += ",biased";
}
Logger.log(new LogEvent(torrent, LOGID, "AZ2-COMPACT PEER: " + new_peer.getString() + extra));
}
valid_meta_peers.add(new_peer);
} catch (Throwable e) {
if (Logger.isEnabled())
Logger.log(new LogEvent(torrent, LOGID, LogEvent.LT_ERROR, "Invalid az2 peer received: " + peer));
}
}
} else if (meta_peers_peek instanceof List) {
// old style non-compact
List meta_peers = (List) meta_peers_peek;
// for every peer
int peers_length = meta_peers.size();
if (Logger.isEnabled()) {
Logger.log(new LogEvent(torrent, LOGID, "ANNOUNCE old style non-compact: num=" + peers_length));
}
if (crypto_flags != null && peers_length != crypto_flags.length) {
crypto_flags = null;
if (Logger.isEnabled())
Logger.log(new LogEvent(torrent, LOGID, LogEvent.LT_ERROR, "Invalid crypto_flags returned: length mismatch"));
}
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");
if (s_ip != null && s_port != null) {
// get the peer ip address
String base_ip = new String((byte[]) s_ip, Constants.DEFAULT_ENCODING);
String ip = AddressUtils.convertToShortForm(base_ip);
if (ip == null) {
// corrupt address, skip
Logger.log(new LogEvent(torrent, LOGID, LogEvent.LT_ERROR, "Skipping invalid address: " + base_ip));
continue;
}
// get the peer port number - should be Long but have seen byte[] on occasion
int peer_port = s_port instanceof byte[] ? Integer.parseInt(new String((byte[]) s_port)) : ((Long) s_port).intValue();
// still can't make outgoing connections that we already can't make
if (peer_port > 65535)
peer_port -= 65536;
if (peer_port < 0)
peer_port += 65536;
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;
if (s_peerid == null) {
// Debug.out(ip + ": tracker did not give peerID in reply");
peer_peer_id = TRTrackerAnnouncerFactoryImpl.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;
if (crypto_flags == null) {
protocol = DownloadAnnounceResultPeer.PROTOCOL_NORMAL;
} else {
protocol = crypto_flags[i] == 0 ? DownloadAnnounceResultPeer.PROTOCOL_NORMAL : DownloadAnnounceResultPeer.PROTOCOL_CRYPT;
}
int udp_port = 0;
int http_port = 0;
TRTrackerAnnouncerResponsePeerImpl new_peer = new TRTrackerAnnouncerResponsePeerImpl(PEPeerSource.PS_BT_TRACKER, peer_peer_id, ip, peer_port, udp_port, http_port, protocol, TRTrackerAnnouncer.AZ_TRACKER_VERSION_1, (short) 0);
if (Logger.isEnabled())
Logger.log(new LogEvent(torrent, LOGID, "NON-COMPACT PEER: " + new_peer.getString()));
valid_meta_peers.add(new_peer);
}
}
} else if (meta_peers_peek instanceof byte[]) {
// byte[] for compact returns
byte[] meta_peers = (byte[]) meta_peers_peek;
String tracker_network = AENetworkClassifier.categoriseAddress(url.getHost());
if (tracker_network == AENetworkClassifier.AT_I2P && (meta_peers.length % 32 == 0)) {
for (int i = 0; i < meta_peers.length; i += 32) {
byte[] i2p_id = new byte[32];
byte[] peer_peer_id = new byte[20];
System.arraycopy(meta_peers, i, i2p_id, 0, 32);
System.arraycopy(meta_peers, i, peer_peer_id, 0, 20);
String hostname = Base32.encode(i2p_id).toLowerCase(Locale.US) + ".b32.i2p";
TRTrackerAnnouncerResponsePeerImpl peer = new TRTrackerAnnouncerResponsePeerImpl(PEPeerSource.PS_BT_TRACKER, peer_peer_id, hostname, 6881, 0, 0, DownloadAnnounceResultPeer.PROTOCOL_NORMAL, TRTrackerAnnouncer.AZ_TRACKER_VERSION_1, (short) 0);
if (Logger.isEnabled())
Logger.log(new LogEvent(torrent, LOGID, "COMPACT PEER: " + peer.getString()));
valid_meta_peers.add(peer);
}
} else {
int entry_size = az_compact == 1 ? 9 : 6;
if (crypto_flags != null && meta_peers.length / entry_size != crypto_flags.length) {
crypto_flags = null;
if (Logger.isEnabled())
Logger.log(new LogEvent(torrent, LOGID, LogEvent.LT_ERROR, "Invalid crypto_flags returned: length mismatch"));
}
int peer_number = 0;
if (Logger.isEnabled()) {
Logger.log(new LogEvent(torrent, LOGID, "ANNOUNCE CompactPeers: num=" + (meta_peers.length / entry_size)));
}
int peers_length = meta_peers.length;
for (int i = 0; i < (peers_length / entry_size) * entry_size; i += entry_size) {
peer_number++;
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 tcp_port = po1 * 256 + po2;
if (tcp_port < 0 || tcp_port > 65535) {
if (Logger.isEnabled())
Logger.log(new LogEvent(torrent, LOGID, LogEvent.LT_ERROR, "Invalid compact peer port given: " + ip + ": " + tcp_port));
continue;
}
byte[] peer_peer_id = TRTrackerAnnouncerFactoryImpl.getAnonymousPeerId(ip, tcp_port);
short protocol;
int udp_port;
if (az_compact == 1) {
int upo1 = 0xFF & meta_peers[i + 6];
int upo2 = 0xFF & meta_peers[i + 7];
udp_port = upo1 * 256 + upo2;
byte flags = meta_peers[i + 8];
protocol = (flags & 0x01) == 0 ? DownloadAnnounceResultPeer.PROTOCOL_NORMAL : DownloadAnnounceResultPeer.PROTOCOL_CRYPT;
} else {
if (crypto_flags == null) {
protocol = DownloadAnnounceResultPeer.PROTOCOL_NORMAL;
} else {
protocol = crypto_flags[peer_number - 1] == 0 ? DownloadAnnounceResultPeer.PROTOCOL_NORMAL : DownloadAnnounceResultPeer.PROTOCOL_CRYPT;
}
udp_port = 0;
}
int http_port = 0;
TRTrackerAnnouncerResponsePeerImpl peer = new TRTrackerAnnouncerResponsePeerImpl(PEPeerSource.PS_BT_TRACKER, peer_peer_id, ip, tcp_port, udp_port, http_port, protocol, TRTrackerAnnouncer.AZ_TRACKER_VERSION_1, (short) 0);
if (Logger.isEnabled())
Logger.log(new LogEvent(torrent, LOGID, "COMPACT PEER: " + peer.getString()));
valid_meta_peers.add(peer);
}
}
} else if (meta_peers_peek instanceof Map) {
if (((Map) meta_peers_peek).size() != 0) {
throw (new IOException("peers missing from response"));
}
} else if (!metaData.containsKey("peers6")) {
// we got nothing useful under peers and no peers6 either
// meh, seen a tracker that doesn't return anything when it has nothing
// throw( new IOException( "peers missing from response" ));
}
final byte[] v6peers = (byte[]) metaData.get("peers6");
if (v6peers != null) {
// 16 bytes for v6 + 2 bytes for port
final int entry_size = 18;
final byte[] rawAddr = new byte[16];
for (int i = 0; i < v6peers.length; i += entry_size) {
System.arraycopy(v6peers, i, rawAddr, 0, 16);
String ip = InetAddress.getByAddress(rawAddr).getHostAddress();
int po1 = 0xFF & v6peers[i + 16];
int po2 = 0xFF & v6peers[i + 17];
int tcp_port = po1 * 256 + po2;
if (tcp_port < 0 || tcp_port > 65535) {
if (Logger.isEnabled()) {
Logger.log(new LogEvent(torrent, LOGID, LogEvent.LT_ERROR, "Invalid compactv6 peer port given: " + ip + ": " + tcp_port));
}
continue;
}
byte[] peer_peer_id = TRTrackerAnnouncerFactoryImpl.getAnonymousPeerId(ip, tcp_port);
short protocol = DownloadAnnounceResultPeer.PROTOCOL_NORMAL;
TRTrackerAnnouncerResponsePeerImpl peer = new TRTrackerAnnouncerResponsePeerImpl(PEPeerSource.PS_BT_TRACKER, peer_peer_id, ip, tcp_port, 0, 0, protocol, TRTrackerAnnouncer.AZ_TRACKER_VERSION_1, (short) 0);
if (Logger.isEnabled()) {
Logger.log(new LogEvent(torrent, LOGID, "COMPACTv6 PEER: " + peer.getString()));
}
valid_meta_peers.add(peer);
}
}
TRTrackerAnnouncerResponsePeerImpl[] peers = new TRTrackerAnnouncerResponsePeerImpl[valid_meta_peers.size()];
valid_meta_peers.toArray(peers);
helper.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 || downloaded_l != null) {
int complete = complete_l == null ? 0 : complete_l.intValue();
int incomplete = incomplete_l == null ? 0 : incomplete_l.intValue();
int downloaded = downloaded_l == null ? -1 : downloaded_l.intValue();
if (complete < 0 || incomplete < 0) {
resp.setFailureReason(MessageText.getString("Tracker.announce.ignorePeerSeed", new String[] { (complete < 0 ? MessageText.getString("MyTorrentsView.seeds") + " == " + complete + ". " : "") + (incomplete < 0 ? MessageText.getString("MyTorrentsView.peers") + " == " + incomplete + ". " : "") }));
} else {
resp.setScrapeResult(complete, incomplete, downloaded);
TRTrackerScraper scraper = TRTrackerScraperFactory.getSingleton();
if (scraper != null) {
TRTrackerScraperResponse scrapeResponse = scraper.scrape(torrent, getTrackerURL());
if (scrapeResponse != null) {
long lNextScrapeTime = scrapeResponse.getNextScrapeStartTime();
long now = SystemTime.getCurrentTime();
long lNewNextScrapeTime = now + TRTrackerScraperResponseImpl.calcScrapeIntervalSecs(0, complete) * 1000L;
// 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);
if (downloaded >= 0) {
scrapeResponse.setCompleted(downloaded);
}
}
}
}
}
return (resp);
} catch (IOException e) {
if (metaData != null) {
byte[] failure_reason_bytes = (byte[]) metaData.get("failure reason");
if (failure_reason_bytes == null) {
Debug.printStackTrace(e);
failure_reason = "error: " + e.getMessage();
} else {
failure_reason = new String(failure_reason_bytes, Constants.DEFAULT_ENCODING);
}
return (new TRTrackerAnnouncerResponseImpl(url, torrent_hash, TRTrackerAnnouncerResponse.ST_REPORTED_ERROR, Math.max(tracker_interval, getErrorRetryInterval()), failure_reason));
}
// decode could fail if the tracker's returned, say, an HTTP response
// indicating server overload
String trace_data;
if (data.length <= 150) {
trace_data = new String(data);
} else {
trace_data = new String(data, 0, 150) + "...";
}
if (Logger.isEnabled())
Logger.log(new LogEvent(torrent, LOGID, LogEvent.LT_ERROR, "TRTrackerAnnouncer::invalid reply: " + trace_data));
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));
}
use of com.biglybt.core.logging.LogEvent in project BiglyBT by BiglySoftware.
the class TrackerChecker method runScrapes.
private void runScrapes() {
TRTrackerBTScraperResponseImpl nextResponseScraping = checkForNextScrape();
if (Logger.isEnabled() && nextResponseScraping != oldResponse && nextResponseScraping != null) {
Logger.log(new LogEvent(TorrentUtils.getDownloadManager(nextResponseScraping.getHash()), LOGID, LogEvent.LT_INFORMATION, "Next scrape will be " + nextResponseScraping.getURL() + " in " + ((nextResponseScraping.getNextScrapeStartTime() - SystemTime.getCurrentTime()) / 1000) + " sec,type=" + (nextResponseScraping.getTrackerStatus().getSupportsMultipeHashScrapes() ? "multi" : "single") + ",active=" + nextResponseScraping.getTrackerStatus().getNumActiveScrapes()));
}
long delay;
if (nextResponseScraping == null) {
// nothing going on, recheck in a min
delay = 60000;
} else {
long scrape_time = nextResponseScraping.getNextScrapeStartTime();
long time_to_scrape = scrape_time - SystemTime.getCurrentTime() + SystemTime.TIME_GRANULARITY_MILLIS;
if (time_to_scrape <= 0) {
if (nextResponseScraping.getTrackerStatus().getNumActiveScrapes() > 0) {
// check if done scraping every 2 seconds, if no other
// scrapes are scheduled. If other scrapes are sceduled,
// we would have got them from checkForNextScrape()
delay = 2000;
} else {
try {
nextResponseScraping.getTrackerStatus().updateSingleHash(nextResponseScraping.getHash(), false);
// pick up next scrape fairly quickly
delay = 0;
} catch (Throwable e) {
Debug.printStackTrace(e);
delay = 30000;
}
}
} else {
delay = time_to_scrape;
if (delay > 30000) {
// don't sleep too long in case new hashes are added etc.
delay = 30000;
}
}
}
nextScrapeCheckOn = SystemTime.getCurrentTime() + delay;
oldResponse = nextResponseScraping;
// use tracker timer/thread pool
TRTrackerBTAnnouncerImpl.tracker_timer.addEvent(nextScrapeCheckOn, this);
}
Aggregations