Exemplo n.º 1
0
 private void CheckMetadata(BencodedString announce, BencodedDictionary info)
 {
     if (announce == null || info == null)
     {
         throw new TorrentException("Invalid metadata, \'announce\'/\'info\' not of expected type.");
     }
 }
Exemplo n.º 2
0
 private void CheckMetadata(BencodedString announce, BencodedDictionary info)
 {
     if (announce == null || info == null)
     {
         throw new TorrentException(string.Format("Invalid metadata, 'announce'/'info' not of expected type."));
     }
 }
Exemplo n.º 3
0
        private void LoadMetadata()
        {
            BencodedDictionary metadata = GetMetadata();

            var announce = metadata["announce"] as BencodedString;

            var info = metadata["info"] as BencodedDictionary;

            CheckMetadata(announce, info);

            var pieceLength = info["piece length"] as BencodedInteger;

            List <byte[]>    checksumList = GetRawChecksums(info, pieceLength);
            BencodedString   name         = GetNameFromInfo(info);
            List <FileEntry> decodedFiles = DecodeFiles(info, name);

            if (metadata.ContainsKey("announce-list"))
            {
                var announceList = (BencodedList)metadata["announce-list"];
                AnnounceList = DecodeAnnounceList(announceList).AsReadOnly();
            }
            AnnounceURL = announce;
            Checksums   = checksumList.AsReadOnly();
            Files       = decodedFiles.AsReadOnly();
            PieceLength = pieceLength;
            PieceCount  = Checksums.Count;
            Name        = name;
            InfoHash    = ComputeInfoHash(info);
            Announces   = CreateAnnouces(AnnounceURL, AnnounceList);
            TotalLength = Files.Sum(f => f.Length);
        }
Exemplo n.º 4
0
        /// <summary>
        ///     Creates a .torrent file with the given data.
        /// </summary>
        /// <param name="name">The name of the file.</param>
        /// <param name="inputFiles">A List'string containing all the files to be added to the .torrent file.</param>
        /// <param name="filesDir">The root directory of all the files in the .torrent file.</param>
        /// <param name="announce">The announce URL of the tracker, in which the .torrent file will be uploaded to.</param>
        /// <param name="announceList">A list of announce URLs.</param>
        /// <param name="pieceLength">The number of bytes in each piece.</param>
        /// <param name="pieces">A list of strings consisting of the concatenation of all 20-byte SHA1 hash values.</param>
        /// <returns>A string representig the content of the .torrent file.</returns>
        public static string Create(string name, List <FileEntry> inputFiles, string filesDir, string announce,
                                    List <string> announceList, int pieceLength, List <byte[]> pieces)
        {
            var clientVersion = Global.Instance.Version;
            var res           = new BencodedDictionary();

            res.Add("announce", new BencodedString(announce));
            var alist = new BencodedList();

            announceList.ForEach(a => alist.Add(new BencodedList {
                new BencodedString(a)
            }));
            res.Add("announce-list", alist);
            res.Add("created by", new BencodedString("rtTorrent/" + clientVersion));
            res.Add("creation date", new BencodedInteger(GetUnixTime()));
            res.Add("encoding", new BencodedString("UTF-8"));

            var info = new BencodedDictionary();

            info.Add("piece length", new BencodedInteger(pieceLength));

            var piecesString = new StringBuilder();

            pieces.ForEach(piece => piece.ForEach(b => piecesString.Append((char)b)));

            info.Add("pieces", new BencodedString(piecesString.ToString()));

            //"1" - the client MUST publish its presence to get other peers ONLY via the trackers explicitly described in the metainfo file
            //"0" - the client may obtain peer from other means, e.g. PEX peer exchange, dht. Here, "private" may be read as "no external peer source".
            //info.Add("private", new BencodedInteger(0));

            if (inputFiles.Count == 1)
            {
                info.Add("name", new BencodedString(name));
                info.Add("length", new BencodedInteger(inputFiles[0].Length));
                //MD5 hash of the file should be added here. The BitTorrent protocol specifies it as NOT needed.
            }
            else
            {
                info.Add("name", new BencodedString(filesDir));
                var files = new BencodedList();

                foreach (var inputFile in inputFiles)
                {
                    var aFile = new BencodedDictionary();
                    aFile.Add("length", new BencodedInteger(inputFile.Length));

                    var filePath = new BencodedList();
                    inputFile.Name.Split(Path.DirectorySeparatorChar).ForEach(
                        dir => filePath.Add(new BencodedString(dir)));
                    aFile.Add("path", filePath);
                    files.Add(aFile);
                }
                info.Add("files", files);
            }
            res.Add("info", info);
            return(res.ToString());
        }
Exemplo n.º 5
0
        private byte[] ComputeInfoHash(BencodedDictionary info)
        {
            var hasher   = SHA1.Create();
            var bencoded = info.ToBencodedString();
            var bytes    = bencoded.Select(c => (byte)c).ToArray();
            var hash     = hasher.ComputeHash(bytes);

            return(hash);
        }
Exemplo n.º 6
0
        private BencodedString GetNameFromInfo(BencodedDictionary info)
        {
            var name = info["name"] as BencodedString;

            if (name == null)
            {
                throw new TorrentException("Invalid metadata in file, \'name\' not of expected type.");
            }
            return(name);
        }
Exemplo n.º 7
0
        private FileEntry CreateTorrentFile(BencodedDictionary file)
        {
            var filePathList = (file["path"] as BencodedList).Select(s => (string)(s as BencodedString)).ToArray();
            var fileLength   = file["length"] as BencodedInteger;

            CheckFileProperties(filePathList, fileLength);
            var filePath    = Path.Combine(filePathList);
            var torrentFile = new FileEntry(filePath, fileLength);

            return(torrentFile);
        }
Exemplo n.º 8
0
        private List <byte[]> GetRawChecksums(BencodedDictionary info, BencodedInteger pieceLength)
        {
            var rawChecksums = (info["pieces"] as BencodedString).Select(c => (byte)c).ToArray();

            if (pieceLength == null || rawChecksums == null || rawChecksums.Length % ChecksumSize != 0)
            {
                throw new TorrentException(
                          "Invalid metadata, \'piece length\'/\'pieces\' not of expected type, or invalid length of \'pieces\'.");
            }
            var slicedChecksums = rawChecksums.Batch(ChecksumSize).Select(e => e.ToArray());

            return(slicedChecksums.ToList());
        }
Exemplo n.º 9
0
 private void CheckMetadata(BencodedDictionary metadata)
 {
     if (metadata == null)
     {
         throw new TorrentException("Invalid metadata.");
     }
     if (!metadata.ContainsKey("announce"))
     {
         throw new TorrentException("Invalid metadata, \'announce\' not found.");
     }
     if (!metadata.ContainsKey("info"))
     {
         throw new TorrentException("Invalid metadata, \'info\' not found.");
     }
 }
Exemplo n.º 10
0
        private List <FileEntry> DecodeFiles(BencodedDictionary info, BencodedString name)
        {
            var decodedFiles = new List <FileEntry>();

            if (info.ContainsKey("files"))
            {
                var files = info["files"] as BencodedList;
                CheckInfoFiles(files);
                foreach (BencodedDictionary file in files)
                {
                    var torrentFile = CreateTorrentFile(file);
                    decodedFiles.Add(torrentFile);
                }
            }
            else
            {
                var fileLength = info["length"] as BencodedInteger;
                CheckFileLength(fileLength);
                decodedFiles.Add(new FileEntry(name, fileLength));
            }
            return(decodedFiles);
        }
Exemplo n.º 11
0
 private BencodedString GetNameFromInfo(BencodedDictionary info)
 {
     var name = info["name"] as BencodedString;
     if (name == null)
         throw new TorrentException(string.Format("Invalid metadata in file, 'name' not of expected type."));
     return name;
 }
Exemplo n.º 12
0
 private byte[] HashBencodeDictionary(BencodedDictionary bencodedDictionary)
 {
     return(new SHA1Managed().ComputeHash(Encoding.GetEncoding(28591).GetBytes(bencodedDictionary.RawValue)));
 }
Exemplo n.º 13
0
        /// <summary>
        /// Creates a .torrent file with the given data.
        /// </summary>
        /// <param name="name">The name of the file.</param>
        /// <param name="inputFiles">A List'string containing all the files to be added to the .torrent file.</param>
        /// <param name="filesDir">The root directory of all the files in the .torrent file.</param>
        /// <param name="announce">The announce URL of the tracker, in which the .torrent file will be uploaded to.</param>
        /// <param name="announceList">A list of announce URLs.</param>
        /// <param name="pieceLength">The number of bytes in each piece.</param>
        /// <param name="pieces">A list of strings consisting of the concatenation of all 20-byte SHA1 hash values.</param>
        /// <returns>A string representig the content of the .torrent file.</returns>
        public static string Create(string name, List<FileEntry> inputFiles, string filesDir, string announce,
                                    List<string> announceList, int pieceLength, List<byte[]> pieces)
        {
            Contract.Requires(name != null);
            Contract.Requires(inputFiles != null);
            Contract.Requires(inputFiles.Count >= 1);
            Contract.Requires(announce != null);
            Contract.Requires(pieces != null);

            var clientVersion = Global.Instance.Version;
            var res = new BencodedDictionary();
            res.Add("announce", new BencodedString(announce));
            var alist = new BencodedList();
            announceList.ForEach(a => alist.Add(new BencodedList {new BencodedString(a)}));
            res.Add("announce-list", alist);
            res.Add("created by", new BencodedString("rtTorrent/" + clientVersion));
            res.Add("creation date", new BencodedInteger(GetUnixTime()));
            res.Add("encoding", new BencodedString("UTF-8"));

            var info = new BencodedDictionary();

            info.Add("piece length", new BencodedInteger(pieceLength));

            var piecesString = new StringBuilder();
            pieces.ForEach(piece => piece.ForEach(b => piecesString.Append((char) b)));

            info.Add("pieces", new BencodedString(piecesString.ToString()));

            //"1" - the client MUST publish its presence to get other peers ONLY via the trackers explicitly described in the metainfo file
            //"0" - the client may obtain peer from other means, e.g. PEX peer exchange, dht. Here, "private" may be read as "no external peer source".
            //info.Add("private", new BencodedInteger(0));

            if (inputFiles.Count == 1)
            {
                info.Add("name", new BencodedString(name));
                info.Add("length", new BencodedInteger(inputFiles[0].Length));
                //MD5 hash of the file should be added here. The BitTorrent protocol specifies it as NOT needed.
            }
            else
            {
                info.Add("name", new BencodedString(filesDir));
                var files = new BencodedList();

                foreach (FileEntry inputFile in inputFiles)
                {
                    var aFile = new BencodedDictionary();
                    aFile.Add("length", new BencodedInteger(inputFile.Length));

                    var filePath = new BencodedList();
                    inputFile.Name.Split(Path.DirectorySeparatorChar).ForEach(
                        dir => filePath.Add(new BencodedString(dir)));
                    aFile.Add("path", filePath);
                    files.Add(aFile);
                }
                info.Add("files", files);
            }
            res.Add("info", info);
            return res.ToString();
        }
Exemplo n.º 14
0
 private void CheckMetadata(BencodedString announce, BencodedDictionary info)
 {
     if (announce == null || info == null)
         throw new TorrentException(string.Format("Invalid metadata, 'announce'/'info' not of expected type."));
 }
Exemplo n.º 15
0
 private void CheckMetadata(BencodedDictionary metadata)
 {
     if (metadata == null)
         throw new TorrentException(string.Format("Invalid metadata."));
     if (!metadata.ContainsKey("announce"))
         throw new TorrentException(string.Format("Invalid metadata, 'announce' not found."));
     if (!metadata.ContainsKey("info"))
         throw new TorrentException(string.Format("Invalid metadata, 'info' not found."));
 }
Exemplo n.º 16
0
 private byte[] ComputeInfoHash(BencodedDictionary info)
 {
     SHA1 hasher = SHA1.Create();
     string bencoded = info.ToBencodedString();
     byte[] bytes = bencoded.Select(c => (byte) c).ToArray();
     byte[] hash = hasher.ComputeHash(bytes);
     return hash;
 }
Exemplo n.º 17
0
 public static IPEndPoint FromBencoded(BencodedDictionary peer)
 {
     return new IPEndPoint(IPAddress.Parse((BencodedString) peer["ip"]),
                           (ushort) (BencodedInteger) peer["port"]);
 }
Exemplo n.º 18
0
 private FileEntry CreateTorrentFile(BencodedDictionary file)
 {
     string[] filePathList = (file["path"] as BencodedList).Select(s => (string) (s as BencodedString)).ToArray();
     var fileLength = file["length"] as BencodedInteger;
     CheckFileProperties(filePathList, fileLength);
     string filePath = Path.Combine(filePathList);
     var torrentFile = new FileEntry(filePath, fileLength);
     return torrentFile;
 }
Exemplo n.º 19
0
 private List<FileEntry> DecodeFiles(BencodedDictionary info, BencodedString name)
 {
     var decodedFiles = new List<FileEntry>();
     if (info.ContainsKey("files"))
     {
         var files = info["files"] as BencodedList;
         CheckInfoFiles(files);
         foreach (BencodedDictionary file in files)
         {
             FileEntry torrentFile = CreateTorrentFile(file);
             decodedFiles.Add(torrentFile);
         }
     }
     else
     {
         var fileLength = info["length"] as BencodedInteger;
         CheckFileLength(fileLength);
         decodedFiles.Add(new FileEntry(name, fileLength));
     }
     return decodedFiles;
 }
Exemplo n.º 20
0
 public static IPEndPoint FromBencoded(BencodedDictionary peer)
 {
     return(new IPEndPoint(IPAddress.Parse((BencodedString)peer["ip"]),
                           (ushort)(BencodedInteger)peer["port"]));
 }
Exemplo n.º 21
0
 private List<byte[]> GetRawChecksums(BencodedDictionary info, BencodedInteger pieceLength)
 {
     byte[] rawChecksums = (info["pieces"] as BencodedString).Select(c=>(byte)c).ToArray();
     if (pieceLength == null || rawChecksums == null || rawChecksums.Length%ChecksumSize != 0)
         throw new TorrentException(
             string.Format(
                 "Invalid metadata, 'piece length'/'pieces' not of expected type, or invalid length of 'pieces'."));
     IEnumerable<byte[]> slicedChecksums = rawChecksums.Batch(ChecksumSize).Select(e => e.ToArray());
     return slicedChecksums.ToList();
 }