public static TrackerBehavior Discover(Tracker tracker) { TrackerBehavior behavior = new TrackerBehavior(tracker); behavior.SupportsScrape = tracker.SupportsScrape; behavior.SupportsMultiScrape = false; behavior.MultiScrapeRange = 0; behavior.MultiScrapeThreshold = -1; behavior.SupportsFullScrape = false; behavior.IndicatesPasskey = false; behavior.IndicatesPrivacy = false; behavior.DefaultInterval = TrackerSettings.DefaultInterval; PeerId peerId1 = CreateDiscoveryPeerId(); PeerId peerId2 = CreateDiscoveryPeerId(); InfoHash infoHash1 = CreateDiscoveryInfoHash(); InfoHash infoHash2 = CreateDiscoveryInfoHash(); if (tracker.Protocol == TrackerProtocol.HTTP || tracker.Protocol == TrackerProtocol.HTTPS) { string[] announcePathFragments = tracker.AnnounceUrl.LocalPath.Split('/'); string announceQueryLower = tracker.AnnounceUrl.Query.ToLower(); if (announcePathFragments.Length > 2) { if (Regex.IsMatch(announcePathFragments[announcePathFragments.Length - 2], @"\A[0-9a-fA-F]*\z")) { behavior.IndicatesPasskey = true; behavior.IndicatesPrivacy = true; goto EndExposureAssessment; } } string passkey = HttpUtility.ParseQueryString(announceQueryLower)["passkey"]; if (!String.IsNullOrEmpty(passkey)) { if (Regex.IsMatch(passkey, @"\A[0-9a-fA-F]*\z")) { behavior.IndicatesPasskey = true; behavior.IndicatesPrivacy = true; } } EndExposureAssessment: ; } if (behavior.SupportsScrape) { try { behavior.DefaultInterval = tracker.CreateAnnounceRequest(infoHash1, peerId1, discoveryPort, 0, 0, 0).GetTransport().GetResponse().Interval; } catch (TrackerFailureException tfe) { string messageLower = tfe.Message.ToLower(); if (messageLower.Contains("client") || messageLower.Contains("protocol")) behavior.IndicatesClientRestriction = true; else behavior.IndicatesRegistration = true; } catch (Exception) { throw; } if (tracker.Protocol == TrackerProtocol.HTTP || tracker.Protocol == TrackerProtocol.HTTPS) { try { HttpScrapeTransport scrapeTestTransport = (HttpScrapeTransport)tracker.CreateScrapeRequest().GetTransport(); HttpWebResponse scrapeTestResponse = (HttpWebResponse)scrapeTestTransport.HttpRequest.GetResponse(); if (scrapeTestResponse.StatusCode == HttpStatusCode.OK) { char[] scrapeStartTestResponseBuffer = new char[httpMultiScrapeResponseStartFragment.Length]; char[] scrapeEndTestResponseBuffer = new char[httpMultiScrapeResponseEndFragment.Length]; using (StreamReader scrapeTestResponseReader = new StreamReader(scrapeTestResponse.GetResponseStream())) { if ( scrapeTestResponseReader.Read(scrapeStartTestResponseBuffer, 0, scrapeStartTestResponseBuffer.Length) == scrapeStartTestResponseBuffer.Length && scrapeTestResponseReader.Read(scrapeEndTestResponseBuffer, 0, scrapeEndTestResponseBuffer.Length) == scrapeEndTestResponseBuffer.Length ) { if (new string(scrapeStartTestResponseBuffer) == httpMultiScrapeResponseStartFragment) { if (scrapeTestResponse.ContentLength != -1 && new string(scrapeEndTestResponseBuffer) != httpMultiScrapeResponseEndFragment) { behavior.ScrapeThreshold = (int)Math.Ceiling((decimal)scrapeTestResponse.ContentLength / (decimal)(tracker.ScrapeUrl.ToString().Length + httpInfoHashQueryFieldSize)); behavior.MultiScrapeThreshold = (int)Math.Ceiling((decimal)scrapeTestResponse.ContentLength / (decimal)httpInfoHashQueryFieldSize); } else { behavior.ScrapeThreshold = TrackerSettings.DefaultScrapeThreshold; behavior.MultiScrapeThreshold = TrackerSettings.DefaultMultiScrapeThreshold; } behavior.SupportsFullScrape = true; } } } } } catch (TrackerFailureException tfe) { if (tfe.Message.ToLower().Contains("client")) behavior.IndicatesClientRestriction = true; else behavior.IndicatesPrivacy = true; } catch (Exception) { throw; } if (!behavior.IndicatesRegistration && !behavior.IndicatesPrivacy) { try { tracker.CreateAnnounceRequest(infoHash2, peerId2, discoveryPort, 0, 0, 0).GetResponse(); IScrapeResponse scrapeResponse = tracker.CreateScrapeRequest(new InfoHash[2] { infoHash1, infoHash2 }).GetResponse(); if (scrapeResponse.Files.ContainsKey(infoHash1) && scrapeResponse.Files.ContainsKey(infoHash2)) { behavior.SupportsMultiScrape = true; behavior.MultiScrapeRange = HttpScrapeTransport.MultiScrapeRange; } } catch (TrackerFailureException tfe) { string mutliScrapeError = tfe.Message.ToLower(); if (mutliScrapeError.Contains("register") && !mutliScrapeError.Contains("pass") && !mutliScrapeError.Contains("key")) behavior.SupportsMultiScrape = true; } } else { // Tracker is private, but multi-scrape is probably enabled behavior.SupportsMultiScrape = true; } } else if (tracker.Protocol == TrackerProtocol.UDP) { behavior.SupportsMultiScrape = true; behavior.MultiScrapeRange = UdpScrapeTransport.MultiScrapeRange; } } return behavior; }
private TrackerBehavior(Tracker tracker) { SupportsScrape = tracker.SupportsScrape; SupportsFullScrape = false; DefaultInterval = TrackerSettings.DefaultInterval; }
public TrackerBehavior this[Tracker tracker] { get { lock (syncRoot) { if (tracker == null) throw new ArgumentNullException("tracker"); if (cache.ContainsKey(tracker.AnnounceUrl)) { BehaviorCacheItem item = cache[tracker.AnnounceUrl]; if (!item.Expired) return item.Behavior; } return null; } } set { lock (syncRoot) { if (tracker == null) throw new ArgumentNullException("tracker"); if (cache.ContainsKey(tracker.AnnounceUrl)) cache[tracker.AnnounceUrl] = new BehaviorCacheItem(value, cache[tracker.AnnounceUrl].LifeTime); else cache.Add(tracker.AnnounceUrl, new BehaviorCacheItem(value)); } } }