internal FastResume(BEncodedDictionary dict) { CheckVersion(dict); CheckContent(dict, InfoHashKey); CheckContent(dict, BitfieldKey); CheckContent(dict, BitfieldLengthKey); // BEP52: Support backwards/forwards compatibility var infoHash = InfoHash.FromMemory(((BEncodedString)dict[InfoHashKey]).AsMemory()); if (infoHash.Span.Length == 20) { InfoHashes = InfoHashes.FromV1(infoHash); } else { InfoHashes = InfoHashes.FromV2(infoHash); } var data = ((BEncodedString)dict[BitfieldKey]).Span; Bitfield = new ReadOnlyBitField(data, (int)((BEncodedNumber)dict[BitfieldLengthKey]).Number); // If we're loading up an older version of the FastResume data then we if (dict.ContainsKey(UnhashedPiecesKey)) { data = ((BEncodedString)dict[UnhashedPiecesKey]).Span; UnhashedPieces = new ReadOnlyBitField(data, Bitfield.Length); } else { UnhashedPieces = new ReadOnlyBitField(Bitfield.Length); } }
public void Add(InfoHashes skey) { var clone = new InfoHash[SKeys.Length + 1]; Array.Copy(SKeys, clone, SKeys.Length); clone[clone.Length - 1] = skey.V1OrV2.Truncate(); SKeys = clone; }
public bool Contains (InfoHashes infoHashes) { CheckDisposed (); if (infoHashes == null) return false; return allTorrents.Exists (m => m.InfoHashes == infoHashes); }
public void Remove(InfoHashes skey) { var clone = new InfoHash[SKeys.Length - 1]; var index = Array.IndexOf(SKeys, skey.V1OrV2.Truncate()); Array.Copy(SKeys, clone, index); Array.Copy(SKeys, index + 1, clone, index, clone.Length - index); SKeys = clone; }
public void DownloadMetadata_Cancelled() { var cts = new CancellationTokenSource(); var engine = new ClientEngine(EngineSettingsBuilder.CreateForTests()); var task = engine.DownloadMetadataAsync(new MagnetLink(InfoHashes.FromV1(new InfoHash(new byte[20]))), cts.Token); cts.Cancel(); Assert.ThrowsAsync <OperationCanceledException> (() => task); }
internal static List <int> Calculate(SHA1 hasher, byte[] addressBytes, InfoHashes infohashes, int count, uint numberOfPieces) { // BEP52: Support V2 torrents var infohash = infohashes.V1; if (infohash == null) { return(new List <int> ()); } byte[] hashBuffer = new byte[24]; // The hash buffer to be used in hashing var results = new List <int> (count); // The results array which will be returned // 1) Convert the bytes into an int32 and make them Network order int ip = IPAddress.HostToNetworkOrder(BitConverter.ToInt32(addressBytes, 0)); // 2) binary AND this value with 0xFFFFFF00 to select the three most sigificant bytes int ipMostSignificant = (int)(0xFFFFFF00 & ip); // 3) Make ipMostSignificant into NetworkOrder uint ip2 = (uint)IPAddress.HostToNetworkOrder(ipMostSignificant); // 4) Copy ip2 into the hashBuffer Buffer.BlockCopy(BitConverter.GetBytes(ip2), 0, hashBuffer, 0, 4); // 5) Copy the infohash into the hashbuffer infohash.Span.CopyTo(hashBuffer.AsSpan(4, 20)); // 6) Keep hashing and cycling until we have AllowedFastPieceCount number of results // Then return that result while (true) { hashBuffer = hasher.ComputeHash(hashBuffer); for (int i = 0; i < 20; i += 4) { uint result = (uint)IPAddress.HostToNetworkOrder(BitConverter.ToInt32(hashBuffer, i)); result %= numberOfPieces; if (result > int.MaxValue) { return(results); } results.Add((int)result); if (count == results.Count) { return(results); } } } }
internal FastResume(InfoHashes infoHashes, ReadOnlyBitField bitfield, ReadOnlyBitField unhashedPieces) { InfoHashes = infoHashes ?? throw new ArgumentNullException(nameof(infoHashes)); Bitfield = new ReadOnlyBitField(bitfield); UnhashedPieces = new ReadOnlyBitField(unhashedPieces); for (int i = 0; i < Bitfield.Length; i++) { if (bitfield[i] && unhashedPieces[i]) { throw new ArgumentException($"The bitfield is set to true at index {i} but that piece is marked as unhashed."); } } }
internal static List <int> Calculate(SHA1 hasher, byte[] addressBytes, InfoHashes infohashes, uint numberOfPieces) { return(Calculate(hasher, addressBytes, infohashes, AllowedFastPieceCount, numberOfPieces)); }
internal async Task StreamAsync(InfoHashes infoHashes, CancellationToken token) => await StreamAsync(await Engine.AddStreamingAsync(new MagnetLink(infoHashes), DownloadDirectory), token);
internal string GetMetadataPath(InfoHashes infoHashes) => Path.Combine(MetadataCacheDirectory, $"{infoHashes.V1OrV2.ToHex ()}.torrent");
/// <summary> /// Returns the full path to the <see cref="FastResume"/> file for the specified torrent. This is /// where data will be written to, or loaded from, when <see cref="AutoSaveLoadFastResume"/> is enabled. /// </summary> /// <param name="infoHashes">The infohashes for the torrent</param> /// <returns></returns> public string GetFastResumePath(InfoHashes infoHashes) => Path.Combine(FastResumeCacheDirectory, $"{infoHashes.V1OrV2.ToHex ()}.fresume");
async Task<bool> RemoveAsync (InfoHashes infoHashes, RemoveMode mode) { await MainLoop; var manager = allTorrents.FirstOrDefault (t => t.InfoHashes == infoHashes); return manager != null && await RemoveAsync (manager, mode); }