/// <summary>
        /// Tries to load the torrent info from the specified file path.
        /// </summary>
        /// <param name="torrentInfoFilePath">The torrent information file path.</param>
        /// <param name="torrentInfo">The torrent information.</param>
        /// <returns>
        /// True if torrent was loaded successfully, false otherwise.
        /// </returns>
        public static bool TryLoad(string torrentInfoFilePath, out TorrentInfo torrentInfo)
        {
            torrentInfoFilePath.MustBeValidFilePath();
            torrentInfoFilePath.MustFileExist();

            return(TryLoad(File.ReadAllBytes(torrentInfoFilePath), out torrentInfo));
        }
        /// <summary>
        /// Starts the specified torrent.
        /// </summary>
        /// <param name="torrentInfo">The torrent information.</param>
        public void Start(TorrentInfo torrentInfo)
        {
            torrentInfo.CannotBeNull();

            TransferManager transfer;

            Debug.WriteLine($"starting torrent {torrentInfo.InfoHash}");

            if (this.IsRunning)
            {
                lock (((IDictionary)this.transfers).SyncRoot)
                {
                    if (!this.transfers.ContainsKey(torrentInfo.InfoHash))
                    {
                        transfer = new TransferManager(this.ListeningPort, torrentInfo, this.throttlingManager, new PersistenceManager(this.BaseDirectory, torrentInfo.Length, torrentInfo.PieceLength, torrentInfo.PieceHashes, torrentInfo.Files));
                        transfer.TorrentHashing  += this.Transfer_TorrentHashing;
                        transfer.TorrentLeeching += this.Transfer_TorrentLeeching;
                        transfer.TorrentSeeding  += this.Transfer_TorrentSeeding;
                        transfer.TorrentStarted  += this.Transfer_TorrentStarted;
                        transfer.TorrentStopped  += this.Transfer_TorrentStopped;
                        transfer.Start();

                        this.transfers.Add(torrentInfo.InfoHash, transfer);
                    }
                    else
                    {
                        throw new TorrentClientException($"Torrent {torrentInfo.InfoHash} is already active.");
                    }
                }
            }
            else
            {
                throw new TorrentClientException("Torrent client is not running.");
            }
        }
示例#3
0
        /// <summary>
        /// Initializes a new instance of the <see cref="TransferManager" /> class.
        /// </summary>
        /// <param name="listeningPort">The port.</param>
        /// <param name="torrentInfo">The torrent information.</param>
        /// <param name="throttlingManager">The throttling manager.</param>
        /// <param name="persistenceManager">The persistence manager.</param>
        public TransferManager(int listeningPort, TorrentInfo torrentInfo, ThrottlingManager throttlingManager, PersistenceManager persistenceManager)
        {
            listeningPort.MustBeGreaterThanOrEqualTo(IPEndPoint.MinPort);
            listeningPort.MustBeLessThanOrEqualTo(IPEndPoint.MaxPort);
            torrentInfo.CannotBeNull();
            throttlingManager.CannotBeNull();
            persistenceManager.CannotBeNull();

            Tracker tracker = null;

            this.PeerId = "-AB1100-" + "0123456789ABCDEF".Random(24);

            Debug.WriteLine($"creating torrent manager for torrent {torrentInfo.InfoHash}");
            Debug.WriteLine($"local peer id {this.PeerId}");

            this.TorrentInfo = torrentInfo;

            this.throttlingManager = throttlingManager;

            this.persistenceManager = persistenceManager;

            // initialize trackers
            foreach (var trackerUri in torrentInfo.AnnounceList)
            {
                if (trackerUri.Scheme == "http" ||
                    trackerUri.Scheme == "https")
                {
                    tracker = new HttpTracker(trackerUri, this.PeerId, torrentInfo.InfoHash, listeningPort);
                }
                else if (trackerUri.Scheme == "udp")
                {
                    tracker = new UdpTracker(trackerUri, this.PeerId, torrentInfo.InfoHash, listeningPort);
                }

                if (tracker != null)
                {
                    tracker.TrackingEvent       = TrackingEvent.Started;
                    tracker.Announcing         += this.Tracker_Announcing;
                    tracker.Announced          += this.Tracker_Announced;
                    tracker.TrackingFailed     += this.Tracker_TrackingFailed;
                    tracker.BytesLeftToDownload = this.TorrentInfo.Length - this.Downloaded;
                    tracker.WantedPeerCount     = 30; // we can handle 30 peers at a time

                    this.trackers.Add(trackerUri, tracker);
                }
                else
                {
                    // unsupported tracker protocol
                    Debug.WriteLine($"unsupported tracker protocol {trackerUri.Scheme}");
                }
            }
        }
示例#4
0
        /// <summary>
        /// Initializes a new instance of the <see cref="TorrentLeechingEventArgs" /> class.
        /// </summary>
        /// <param name="torrentInfo">The torrent information.</param>
        public TorrentLeechingEventArgs(TorrentInfo torrentInfo)
        {
            torrentInfo.CannotBeNull();

            this.TorrentInfo = torrentInfo;
        }
        /// <summary>
        /// Initializes a new instance of the <see cref="TorrentStartedEventArgs" /> class.
        /// </summary>
        /// <param name="torrentInfo">The torrent information.</param>
        public TorrentStartedEventArgs(TorrentInfo torrentInfo)
        {
            torrentInfo.CannotBeNull();

            this.TorrentInfo = torrentInfo;
        }
        /// <summary>
        /// Tries to load the torrent info from the specified binary data.
        /// </summary>
        /// <param name="data">The data.</param>
        /// <param name="torrentInfo">The torrent information.</param>
        /// <returns>True if torrent was loaded successfully, false otherwise.</returns>
        public static bool TryLoad(byte[] data, out TorrentInfo torrentInfo)
        {
            data.CannotBeNullOrEmpty();

            BEncodedValue          value;
            BEncodedDictionary     general;
            BEncodedDictionary     info;
            List <TorrentFileInfo> files = new List <TorrentFileInfo>();
            long           pieceLength;
            List <string>  pieceHashes = new List <string>();
            bool           isPrivate   = false;
            Uri            tmpUri;
            List <Uri>     announceList = new List <Uri>();
            DateTime?      creationDate = null;
            string         comment      = null;
            string         createdBy    = null;
            Encoding       encoding     = Encoding.ASCII;
            string         filePath;
            long           fileLength = 0;
            string         fileHash;
            string         tmpString;
            BEncodedString infoKey         = new BEncodedString("info");
            BEncodedString pieceLengthKey  = new BEncodedString("piece length");
            BEncodedString piecesKey       = new BEncodedString("pieces");
            BEncodedString privateKey      = new BEncodedString("private");
            BEncodedString nameKey         = new BEncodedString("name");
            BEncodedString lengthKey       = new BEncodedString("length");
            BEncodedString md5sumKey       = new BEncodedString("md5sum");
            BEncodedString filesKey        = new BEncodedString("files");
            BEncodedString pathKey         = new BEncodedString("path");
            BEncodedString announceKey     = new BEncodedString("announce");
            BEncodedString announceListKey = new BEncodedString("announce-list");
            BEncodedString creationDateKey = new BEncodedString("creation date");
            BEncodedString commentKey      = new BEncodedString("comment");
            BEncodedString createdByKey    = new BEncodedString("created by");
            BEncodedString encodingKey     = new BEncodedString("encoding");

            torrentInfo = null;

            try
            {
                value = BEncodedValue.Decode(data);
            }
            catch (BEncodingException)
            {
                return(false);
            }

            if (value is BEncodedDictionary)
            {
                general = value as BEncodedDictionary;

                if (general.ContainsKey(infoKey) &&
                    general[infoKey] is BEncodedDictionary)
                {
                    info = general[infoKey] as BEncodedDictionary;

                    // piece length
                    if (info.ContainsKey(pieceLengthKey) &&
                        info[pieceLengthKey] is BEncodedNumber)
                    {
                        pieceLength = info[pieceLengthKey].As <BEncodedNumber>().Number;
                    }
                    else
                    {
                        return(false);
                    }

                    // pieces
                    if (info.ContainsKey(piecesKey) &&
                        info[piecesKey] is BEncodedString &&
                        info[piecesKey].As <BEncodedString>().TextBytes.Length % 20 == 0)
                    {
                        for (int i = 0; i < info[piecesKey].As <BEncodedString>().TextBytes.Length; i += 20)
                        {
                            byte[] tmpBytes = new byte[20];

                            Array.Copy(info[piecesKey].As <BEncodedString>().TextBytes, i, tmpBytes, 0, tmpBytes.Length);

                            pieceHashes.Add(tmpBytes.ToHexaDecimalString());
                        }

                        if (pieceHashes.Count == 0)
                        {
                            return(false);
                        }
                    }
                    else
                    {
                        return(false);
                    }

                    // is private
                    if (info.ContainsKey(privateKey) &&
                        info[privateKey] is BEncodedNumber)
                    {
                        isPrivate = info[privateKey].As <BEncodedNumber>().Number == 1;
                    }

                    // files
                    if (info.ContainsKey(nameKey) &&
                        info[nameKey] is BEncodedString &&
                        info.ContainsKey(lengthKey) &&
                        info[lengthKey] is BEncodedNumber)
                    {
                        // single file
                        filePath   = info[nameKey].As <BEncodedString>().Text;
                        fileLength = info[lengthKey].As <BEncodedNumber>().Number;

                        if (info.ContainsKey(md5sumKey) &&
                            info[md5sumKey] is BEncodedString)
                        {
                            fileHash = info[md5sumKey].As <BEncodedString>().Text;
                        }
                        else
                        {
                            fileHash = null;
                        }

                        files.Add(new TorrentFileInfo(filePath, fileHash, fileLength));
                    }
                    else if (info.ContainsKey(nameKey) &&
                             info[nameKey] is BEncodedString &&
                             info.ContainsKey(filesKey) &&
                             info[filesKey] is BEncodedList)
                    {
                        tmpString = info[nameKey].As <BEncodedString>().Text;

                        // multi file
                        foreach (var item in info[filesKey].As <BEncodedList>())
                        {
                            if (item is BEncodedDictionary &&
                                item.As <BEncodedDictionary>().ContainsKey(pathKey) &&
                                item.As <BEncodedDictionary>()[pathKey] is BEncodedList &&
                                item.As <BEncodedDictionary>()[pathKey].As <BEncodedList>().All(x => x is BEncodedString) &&
                                item.As <BEncodedDictionary>().ContainsKey(lengthKey) &&
                                item.As <BEncodedDictionary>()[lengthKey] is BEncodedNumber)
                            {
                                filePath   = Path.Combine(tmpString, Path.Combine(item.As <BEncodedDictionary>()[pathKey].As <BEncodedList>().Select(x => x.As <BEncodedString>().Text).ToArray()));
                                fileLength = item.As <BEncodedDictionary>()[lengthKey].As <BEncodedNumber>().Number;

                                if (item.As <BEncodedDictionary>().ContainsKey(md5sumKey) &&
                                    item.As <BEncodedDictionary>()[md5sumKey] is BEncodedString)
                                {
                                    fileHash = item.As <BEncodedDictionary>()[md5sumKey].As <BEncodedString>().Text;
                                }
                                else
                                {
                                    fileHash = null;
                                }

                                files.Add(new TorrentFileInfo(filePath, fileHash, fileLength));
                            }
                            else
                            {
                                return(false);
                            }
                        }

                        if (files.Count == 0)
                        {
                            return(false);
                        }
                    }
                    else
                    {
                        return(false);
                    }
                }
                else
                {
                    return(false);
                }

                // announce
                if (general.ContainsKey(announceKey) &&
                    general[announceKey] is BEncodedString &&
                    Uri.TryCreate(general[announceKey].As <BEncodedString>().Text, UriKind.Absolute, out tmpUri))
                {
                    announceList.Add(tmpUri);
                }
                else
                {
                    return(false);
                }

                // announce list
                if (general.ContainsKey(announceListKey) &&
                    general[announceListKey] is BEncodedList)
                {
                    foreach (var item in general[announceListKey].As <BEncodedList>())
                    {
                        if (item is BEncodedList)
                        {
                            foreach (var item2 in item.As <BEncodedList>())
                            {
                                if (Uri.TryCreate(item2.As <BEncodedString>().Text, UriKind.Absolute, out tmpUri))
                                {
                                    announceList.Add(tmpUri);
                                }
                            }
                        }
                    }

                    announceList = announceList.Select(x => x.AbsoluteUri).Distinct().Select(x => new Uri(x)).ToList();
                }

                // creation adte
                if (general.ContainsKey(creationDateKey) &&
                    general[creationDateKey] is BEncodedNumber)
                {
                    creationDate = new DateTime(1970, 1, 1, 0, 0, 0, 0).AddSeconds(general[creationDateKey].As <BEncodedNumber>().Number).ToLocalTime();
                }

                // comment
                if (general.ContainsKey(commentKey) &&
                    general[commentKey] is BEncodedString)
                {
                    comment = general[commentKey].As <BEncodedString>().Text;
                }

                // created by
                if (general.ContainsKey(createdByKey) &&
                    general[createdByKey] is BEncodedString)
                {
                    createdBy = general[createdByKey].As <BEncodedString>().Text;
                }

                // encoding
                if (general.ContainsKey(encodingKey) &&
                    general[encodingKey] is BEncodedString)
                {
                    if (general[encodingKey].As <BEncodedString>().Text == "UTF8")
                    {
                        encoding = Encoding.UTF8;
                    }
                }

                torrentInfo = new TorrentInfo(
                    general,
                    info.Encode().CalculateSha1Hash().ToHexaDecimalString(),
                    pieceLength,
                    new ReadOnlyCollection <string>(pieceHashes),
                    isPrivate,
                    new ReadOnlyCollection <Uri>(announceList),
                    creationDate,
                    comment,
                    createdBy,
                    encoding,
                    new ReadOnlyCollection <TorrentFileInfo>(files));

                return(true);
            }
            else
            {
                return(false);
            }
        }