예제 #1
0
 public void Load(BDictionary data)
 {
     UserName  = data.Get <BString>("uname").Value.ToString();
     Country   = data.Get <BString>("uctry").Value.ToString();
     TimeZone  = data.Get <BString>("utz").Value.ToString();
     Languages = data.Get <BString>("ulangs").Value.ToString();
 }
예제 #2
0
        private void OnRecvAnnouncePeerQuery(IPEndPoint ipinfo, BDictionary data)
        {
            var t    = data.Get <BString>("t");
            var args = data.Get <BDictionary>("a");

            var id          = args.Get <BString>("id");
            var infoHash    = new DHTId(args.Get <BString>("info_hash"));
            var impliedPort = args.Get <BNumber>("implied_port");
            int port        = (impliedPort != null && impliedPort.Value == 1) ? ipinfo.Port : (int)args.Get <BNumber>("port").Value;

            var remoteNode = new DHTNode(id.Value, ipinfo);

            UpdateRoutingTable(remoteNode);

#if DEBUG_DHT_INTERNALS
            fLogger.WriteDebug("Receive `announce_peer` query from {0} for {1}", remoteNode.ToString(), infoHash.ToString());
#endif

            // skip response for another infohash query
            if (infoHash == fSearchInfoHash)
            {
                // receive `announce_peer` query for our infohash
                var nodesList = fRoutingTable.GetClosest(infoHash.Data);
                Send(ipinfo, DHTMessage.CreateAnnouncePeerResponse(t, fLocalID, nodesList));

                if (PeersFound != null)
                {
                    PeersFound(this, new PeersFoundEventArgs(new List <IPEndPoint>()
                    {
                        ipinfo
                    }));
                }
            }
        }
예제 #3
0
        /// <summary>
        /// Parses trackers (announce URLs) from a torrent.
        /// </summary>
        /// <param name="data">The torrent data to parse trackers from.</param>
        /// <param name="encoding"></param>
        /// <returns>A list of list of trackers (announce URLs).</returns>
        protected virtual IList <IList <string> > ParseTrackers(BDictionary data, Encoding encoding)
        {
            var trackerList = new List <IList <string> >();
            var primary     = new List <string>();

            trackerList.Add(primary);

            // Get single 'announce' url and add it to the primary list if there is any
            var announce = data.Get <BString>(TorrentFields.Announce)?.ToString(encoding);

            if (!string.IsNullOrEmpty(announce))
            {
                primary.Add(announce);
            }

            // Get the 'announce-list' list´s
            var announceLists = data.Get <BList>(TorrentFields.AnnounceList)?.AsType <BList>() as IList <BList>;

            if (announceLists?.Any() == true)
            {
                // Add the first list to the primary list and remove duplicates
                primary.AddRange(announceLists.First().AsStrings(encoding));
                trackerList[0] = primary.Distinct().ToList();

                // Add the other lists to the lists of lists of announce urls
                trackerList.AddRange(
                    announceLists.Skip(1)
                    .Select(x => x.AsStrings(encoding).ToList()));
            }

            return(trackerList);
        }
예제 #4
0
        private void OnRecvAnnouncePeerQuery(IPEndPoint ipinfo, BDictionary data)
        {
            var t    = data.Get <BString>("t");
            var args = data.Get <BDictionary>("a");

            var id          = args.Get <BString>("id");
            var infoHash    = args.Get <BString>("info_hash");
            var impliedPort = args.Get <BNumber>("implied_port");
            int port        = (impliedPort != null && impliedPort.Value == 1) ? ipinfo.Port : (int)args.Get <BNumber>("port").Value;

            fLogger.WriteDebug("Receive `announce_peer` query from {0} [{1}] for {2}", ipinfo.ToString(), id.Value.ToHexString(), infoHash.Value.ToHexString());

            fRoutingTable.UpdateNode(new DHTNode(id.Value, ipinfo));

            if (!Algorithms.ArraysEqual(infoHash.Value, fSearchInfoHash))
            {
                // skip response for another infohash query
                return;
            }

            // receive `announce_peer` query for our infohash
            var nodesList = fRoutingTable.FindNodes(infoHash.Value);

            Send(ipinfo, DHTMessage.CreateAnnouncePeerResponse(t, fLocalID, nodesList));
        }
예제 #5
0
        /// <summary>
        /// Parses file info for multi-file torrents.
        /// </summary>
        /// <param name="info">The 'info'-dictionary of a torrent.</param>
        /// <param name="encoding"></param>
        /// <returns>The file info.</returns>
        protected virtual MultiFileInfoList ParseMultiFileInfo(BDictionary info, Encoding encoding)
        {
            if (!info.ContainsKey(TorrentInfoFields.Files))
            {
                return(null);
            }

            var list = new MultiFileInfoList
            {
                DirectoryName     = info.Get <BString>(TorrentInfoFields.Name)?.ToString(encoding),
                DirectoryNameUtf8 = info.Get <BString>(TorrentInfoFields.NameUtf8)?.ToString(encoding)
            };

            var fileInfos = info.Get <BList>(TorrentInfoFields.Files).Cast <BDictionary>()
                            .Select(x => new MultiFileInfo
            {
                FileSize = x.Get <BNumber>(TorrentFilesFields.Length),
                Path     = x.Get <BList>(TorrentFilesFields.Path)?.AsStrings(encoding).ToList(),
                PathUtf8 = x.Get <BList>(TorrentFilesFields.PathUtf8)?.AsStrings(Encoding.UTF8).ToList(),
                Md5Sum   = x.Get <BString>(TorrentFilesFields.Md5Sum)?.ToString(encoding)
            });

            list.AddRange(fileInfos);

            return(list);
        }
예제 #6
0
        private void OnRecvResponseX(IPEndPoint ipinfo, BDictionary data)
        {
            var tid          = data.Get <BString>("t");
            var returnValues = data.Get <BDictionary>("r");

            var id         = returnValues.Get <BString>("id");
            var tokStr     = returnValues.Get <BString>("token");
            var valuesList = returnValues.Get <BList>("values");
            var nodesStr   = returnValues.Get <BString>("nodes");

            if (id == null || id.Length == 0)
            {
                // response is invalid
                return;
            }

            fRoutingTable.UpdateNode(new DHTNode(id.Value, ipinfo));

            // according to bep_????, most types of response contain a list of nodes
            ProcessNodesStr(ipinfo, nodesStr);

            // define type of response by transactionId of query/response
            QueryType queryType = CheckTransaction(tid);

            bool canAnnounce = false;

            switch (queryType)
            {
            case QueryType.ping:
                RaisePeerPinged(ipinfo, id.Value);
                break;

            case QueryType.find_node:
                break;

            case QueryType.get_peers:
                if (tokStr != null && tokStr.Length != 0)
                {
                    if (!ProcessValuesStr(ipinfo, valuesList))
                    {
                        canAnnounce = true;
                    }
                }
                break;

            case QueryType.announce_peer:
                break;

            case QueryType.none:
                // TransactionId bad or unknown
                RaiseResponseReceived(ipinfo, id.Value, data);
                break;
            }

            if (canAnnounce)
            {
                SendAnnouncePeerQuery(ipinfo, fSearchInfoHash, 1, fLocalIP.Port, tokStr);
            }
        }
예제 #7
0
        private void OnRecvResponseX(IPEndPoint ipinfo, DHTResponseMessage msg)
        {
            if (msg == null)
            {
                return;
            }

            BDictionary data = msg.Data;

            var tid = data.Get <BString>("t");

            var returnValues = data.Get <BDictionary>("r");

            if (returnValues == null)
            {
                // response is invalid
                return;
            }

            BString id         = returnValues.Get <BString>("id");
            BString tokStr     = returnValues.Get <BString>("token");
            BList   valuesList = returnValues.Get <BList>("values");
            BString nodesStr   = returnValues.Get <BString>("nodes");

            var remoteNode = new DHTNode(id.Value, ipinfo);

            UpdateRoutingTable(remoteNode);

            // define type of response by transactionId of query/response
            QueryType queryType = fTransactions.CheckQuery(tid);

            switch (queryType)
            {
            case QueryType.Ping:
                OnRecvPingResponse(remoteNode);
                break;

            case QueryType.FindNode:
                OnRecvFindNodeResponse(remoteNode, nodesStr);
                break;

            case QueryType.GetPeers:
                OnRecvGetPeersResponse(remoteNode, nodesStr, valuesList, tokStr);
                break;

            case QueryType.AnnouncePeer:
                OnRecvAnnouncePeerResponse(remoteNode);
                break;

            case QueryType.None:
                // TransactionId bad or unknown
                OnRecvCustomResponse(remoteNode, data);
                break;
            }
        }
예제 #8
0
        public void Load(BDictionary data)
        {
            if (data == null)
            {
                throw new ArgumentNullException("data");
            }

            UserName  = data.Get <BString>("uname").ToString();
            Country   = data.Get <BString>("uctry").ToString();
            TimeZone  = data.Get <BString>("utz").ToString();
            Languages = data.Get <BString>("ulangs").ToString();
        }
예제 #9
0
        private void OnRecvPingQuery(IPEndPoint ipinfo, BDictionary data)
        {
            var t    = data.Get <BString>("t");
            var args = data.Get <BDictionary>("a");

            var id = args.Get <BString>("id");

            fLogger.WriteDebug("Receive `ping` query from {0} [{1}]", ipinfo.ToString(), id.Value.ToHexString());

            fRoutingTable.UpdateNode(new DHTNode(id.Value, ipinfo));

            Send(ipinfo, DHTMessage.CreatePingResponse(t, fLocalID));
        }
예제 #10
0
        /// <summary>
        /// Parses file info for single-file torrents.
        /// </summary>
        /// <param name="info">The 'info'-dictionary of a torrent.</param>
        /// <param name="encoding"></param>
        /// <returns>The file info.</returns>
        protected virtual SingleFileInfo ParseSingleFileInfo(BDictionary info, Encoding encoding)
        {
            if (!info.ContainsKey(TorrentInfoFields.Length))
            {
                return(null);
            }

            return(new SingleFileInfo
            {
                FileName = info.Get <BString>(TorrentInfoFields.Name)?.ToString(encoding),
                FileSize = info.Get <BNumber>(TorrentInfoFields.Length),
                Md5Sum = info.Get <BString>(TorrentInfoFields.Md5Sum)?.ToString(encoding)
            });
        }
예제 #11
0
        /// <summary>
        /// Parses trackers (announce URLs) from a torrent.
        /// </summary>
        /// <param name="data">The torrent data to parse trackers from.</param>
        /// <param name="encoding"></param>
        /// <returns>A list of list of trackers (announce URLs).</returns>
        protected virtual IList <IList <string> > ParseTrackers(BDictionary data, Encoding encoding)
        {
            // Specification: http://bittorrent.org/beps/bep_0012.html

            var trackerList = new List <IList <string> >();
            var primary     = new List <string>();

            trackerList.Add(primary);

            // Get single 'announce' url and add it to the primary list if there is any
            var announce = data.Get <BString>(TorrentFields.Announce)?.ToString(encoding);

            if (!string.IsNullOrEmpty(announce))
            {
                primary.Add(announce);
            }

            // Get the 'announce-list' list's
            var announceLists = data.Get <BList>(TorrentFields.AnnounceList);

            if (announceLists == null)
            {
                return(trackerList);
            }

            // According to the specification it should be a list of lists
            if (announceLists.All(x => x is BList))
            {
                var lists = announceLists.AsType <BList>() as IList <BList>;
                if (lists.Any())
                {
                    // Add the first list to the primary list and remove duplicates
                    primary.AddRange(lists.First().AsStrings(encoding));
                    trackerList[0] = primary.Distinct().ToList();

                    // Add the other lists to the lists of lists of announce urls
                    trackerList.AddRange(lists.Skip(1).Select(x => x.AsStrings(encoding).ToList()));
                }
            }
            // It's not following the specification, it's strings instead of lists
            else if (ParseMode == TorrentParserMode.Tolerant && announceLists.All(x => x is BString))
            {
                // Add them all to the first list
                primary.AddRange(announceLists.AsStrings(encoding));
                trackerList[0] = primary.Distinct().ToList();
            }

            return(trackerList);
        }
예제 #12
0
        public void SingleFileInfo_IsParsed(long length, string fileName, string fileNameUtf8, string md5Sum)
        {
            // Arrange
            ParsedData = ValidSingleFileTorrentData;
            var info = ParsedData.Get <BDictionary>(TorrentFields.Info);

            info[TorrentInfoFields.Length]   = (BNumber)length;
            info[TorrentInfoFields.Name]     = (BString)fileName;
            info[TorrentInfoFields.NameUtf8] = (BString)fileNameUtf8;
            info[TorrentInfoFields.Md5Sum]   = (BString)md5Sum;

            // Act
            var parser  = new TorrentParser(BencodeParser);
            var torrent = parser.Parse((BencodeReader)null);

            // Assert
            torrent.Files.Should().BeNull();
            torrent.FileMode.Should().Be(TorrentFileMode.Single);
            torrent.TotalSize.Should().Be(length);
            torrent.File.Should().NotBeNull();
            torrent.File.FileSize.Should().Be(length);
            torrent.File.FileName.Should().Be(fileName);
            torrent.File.FileNameUtf8.Should().Be(fileNameUtf8);
            torrent.File.Md5Sum.Should().Be(md5Sum);
        }
예제 #13
0
        private void OnRecvFindNodeQuery(IPEndPoint ipinfo, BDictionary data)
        {
            var t    = data.Get <BString>("t");
            var args = data.Get <BDictionary>("a");

            var id     = args.Get <BString>("id");
            var target = args.Get <BString>("target");

            fLogger.WriteDebug("Receive `find_node` query from {0} [{1}]", ipinfo.ToString(), id.Value.ToHexString());

            fRoutingTable.UpdateNode(new DHTNode(id.Value, ipinfo));

            var nodesList = fRoutingTable.FindNodes(target.Value);

            Send(ipinfo, DHTMessage.CreateFindNodeResponse(t, fLocalID, nodesList));
        }
예제 #14
0
        public void Add_NullStringValue_ResultsInEmptyBString()
        {
            var dict = new BDictionary {
                { "key", (string)null }
            };

            dict.Get <BString>("key").Value.ToArray().Should().BeEmpty();
        }
예제 #15
0
        private void OnRecvPingQuery(IPEndPoint ipinfo, BDictionary data)
        {
            var t    = data.Get <BString>("t");
            var args = data.Get <BDictionary>("a");

            var id = args.Get <BString>("id");

            var remoteNode = new DHTNode(id.Value, ipinfo);

            UpdateRoutingTable(remoteNode);

#if DEBUG_DHT_INTERNALS
            fLogger.WriteDebug("Receive `ping` query from {0}", remoteNode.ToString());
#endif

            Send(ipinfo, DHTMessage.CreatePingResponse(t, fLocalID));
        }
예제 #16
0
        private void OnRecvGetPeersQuery(IPEndPoint ipinfo, BDictionary data)
        {
            var t    = data.Get <BString>("t");
            var args = data.Get <BDictionary>("a");

            var id       = args.Get <BString>("id");
            var infoHash = args.Get <BString>("info_hash");

            fLogger.WriteDebug("Receive `get_peers` query from {0} [{1}] for {2}", ipinfo.ToString(), id.Value.ToHexString(), infoHash.Value.ToHexString());

            fRoutingTable.UpdateNode(new DHTNode(id.Value, ipinfo));

            var neighbor  = DHTHelper.GetNeighbor(infoHash.Value, fLocalID);
            var peersList = (Algorithms.ArraysEqual(infoHash.Value, fSearchInfoHash)) ? fPeersHolder.GetPeersList() : null;
            var nodesList = fRoutingTable.FindNodes(infoHash.Value);

            Send(ipinfo, DHTMessage.CreateGetPeersResponse(t, neighbor, infoHash.Value, peersList, nodesList));
        }
예제 #17
0
 public void RequestScrape(NetworkManager network)
 {
     if (IsScrapeUpdated)
     {
         return;
     }
     try
     {
         string scrapeUrl = File.GenerateScrapeUrlString(Client.HashUpperCase);
         if (string.IsNullOrEmpty(scrapeUrl))
         {
             log.Info("This tracker doesnt seem to support scrape");
         }
         Uri url = new Uri(scrapeUrl);
         Tracker = network.MakeWebRequest(url, Client.HttpProtocol, Client.Headers);
         if (Tracker != null && Tracker.Dico != null)
         {
             BDictionary dico = Tracker.Dico;
             if (dico["failure reason"] != null)
             {
                 log.Error($"Tracker Error : {dico["failure reason"]}");
                 return;
             }
             log.Info("---------- Scrape Info -----------");
             BDictionary dicoFiles  = dico.Get <BDictionary>("files");
             string      infoHash   = Encoding.GetEncoding(0x4e4).GetString(File.InfoHashBytes);
             BDictionary dicoHashes = dicoFiles.Get <BDictionary>(infoHash);
             if (dicoHashes != null)
             {
                 Seeders  = -1;
                 Leechers = -1;
                 log.Info("complete: " + dicoHashes["complete"]);
                 log.Info("downloaded: " + dicoHashes["downloaded"]);
                 log.Info("incomplete: " + dicoHashes["incomplete"]);
                 int parseInt;
                 if (int.TryParse(dicoHashes["complete"].ToString(), out parseInt))
                 {
                     Seeders = parseInt;
                 }
                 if (int.TryParse(dicoHashes["incomplete"].ToString(), out parseInt))
                 {
                     Leechers = parseInt;
                 }
                 IsScrapeUpdated = true;
             }
             else
             {
                 log.Info($"Scrape returned : '{dicoFiles[infoHash]}'");
             }
         }
     }
     catch (Exception ex)
     {
         log.Error(ex, "RequestScrape Error");
     }
 }
예제 #18
0
        private void OnRecvFindNodeQuery(IPEndPoint ipinfo, BDictionary data)
        {
            var t    = data.Get <BString>("t");
            var args = data.Get <BDictionary>("a");

            var id     = args.Get <BString>("id");
            var target = args.Get <BString>("target");

            var remoteNode = new DHTNode(id.Value, ipinfo);

            UpdateRoutingTable(remoteNode);

#if DEBUG_DHT_INTERNALS
            fLogger.WriteDebug("Receive `find_node` query from {0}", remoteNode.ToString());
#endif

            var nodesList = fRoutingTable.GetClosest(target.Value);
            Send(ipinfo, DHTMessage.CreateFindNodeResponse(t, fLocalID, nodesList));
        }
예제 #19
0
        public void MergeWith_DictionaryWithNewKeyIsAdded()
        {
            var dict1 = new BDictionary {
                { "main", new BDictionary {
                      { "key", "value" }
                  } }
            };
            var dict2 = new BDictionary {
                { "main2", new BDictionary {
                      { "key2", "value2" }
                  } }
            };

            dict1.MergeWith(dict2);

            dict1.Should().HaveCount(2);
            dict1.Get <BDictionary>("main").Should().HaveCount(1).And.ContainKeys("key");
            dict1.Get <BDictionary>("main2").Should().HaveCount(1).And.ContainKeys("key2");
        }
예제 #20
0
        private void OnRecvPingQuery(IPEndPoint ipinfo, BDictionary data, bool similar)
        {
            var t    = data.Get <BString>("t");
            var args = data.Get <BDictionary>("a");

            var id = args.Get <BString>("id");

            fLogger.WriteDebug("Receive `ping` query from {0} [{1}]", ipinfo.ToString(), id.Value.ToHexString());

            fRoutingTable.UpdateNode(new DHTNode(id.Value, ipinfo));

            // FIXME: temp debug code
            if (similar)
            {
                fLogger.WriteDebug(">>>>>>>>>>>> Found a similar peer! " + ipinfo.ToString());
            }

            Send(ipinfo, DHTMessage.CreatePingResponse(t, fLocalID));
        }
예제 #21
0
        private void OnRecvErrorX(IPEndPoint ipinfo, BDictionary data)
        {
            var errData = data.Get <BList>("e");

            if (errData != null && errData.Count != 0)
            {
                var errCode = errData.Get <BNumber>(0);
                var errText = errData.Get <BString>(1);
                fLogger.WriteDebug("DHT error receive: " + errCode + " / " + errText);
            }
        }
예제 #22
0
        private void OnRecvGetPeersQuery(IPEndPoint ipinfo, BDictionary data)
        {
            var t    = data.Get <BString>("t");
            var args = data.Get <BDictionary>("a");

            var id       = args.Get <BString>("id");
            var infoHash = new DHTId(args.Get <BString>("info_hash"));

            var remoteNode = new DHTNode(id.Value, ipinfo);

            UpdateRoutingTable(remoteNode);

#if DEBUG_DHT_INTERNALS
            fLogger.WriteDebug("Receive `get_peers` query from {0} for {1}", remoteNode.ToString(), infoHash.ToString());
#endif

            var neighbor  = DHTNode.GetNeighbor(infoHash.Data, fLocalID.Data);
            var peersList = (infoHash == fSearchInfoHash) ? fPeersHolder.GetPeersList() : null;
            var nodesList = fRoutingTable.GetClosest(infoHash.Data);
            Send(ipinfo, DHTMessage.CreateGetPeersResponse(t, neighbor, infoHash, peersList, nodesList));
        }
예제 #23
0
        /// <summary>
        /// Creates a torrent by reading the relevant data from the <see cref="BDictionary"/>.
        /// </summary>
        /// <param name="data">The torrent bencode data.</param>
        /// <returns>A <see cref="Torrent"/> matching the input.</returns>
        protected Torrent CreateTorrent(BDictionary data)
        {
            if (ParseMode == TorrentParserMode.Strict)
            {
                EnsureValidTorrentData(data);
            }

            var info = data.Get <BDictionary>(TorrentFields.Info);

            var encoding = ParseEncoding(data.Get <BString>(TorrentFields.Encoding)) ?? BencodeParser.Encoding;

            var torrent = new Torrent(info)
            {
                IsPrivate = info.Get <BNumber>(TorrentInfoFields.Private) == 1,
                PieceSize = info.Get <BNumber>(TorrentInfoFields.PieceLength),
                Pieces    = info.Get <BString>(TorrentInfoFields.Pieces)?.Value.ToArray() ?? new byte[0],

                Comment      = data.Get <BString>(TorrentFields.Comment)?.ToString(encoding),
                CreatedBy    = data.Get <BString>(TorrentFields.CreatedBy)?.ToString(encoding),
                Encoding     = ParseEncoding(data.Get <BString>(TorrentFields.Encoding)),
                CreationDate = data.Get <BNumber>(TorrentFields.CreationDate),

                File  = ParseSingleFileInfo(info, encoding),
                Files = ParseMultiFileInfo(info, encoding),

                Trackers = ParseTrackers(data, encoding),

                ExtraFields = ParseAnyExtraFields(data, encoding)
            };

            return(torrent);
        }
예제 #24
0
        public void OriginalInfoHashBytes_IsSet()
        {
            // Arrange
            ParsedData = ValidSingleFileTorrentData;
            var expectedInfoHashBytes = TorrentUtil.CalculateInfoHashBytes(ParsedData.Get <BDictionary>("info"));

            // Act
            var parser  = new TorrentParser(BencodeParser);
            var torrent = parser.Parse((BencodeReader)null);

            // Assert
            torrent.OriginalInfoHashBytes.Should().Equal(expectedInfoHashBytes);
        }
예제 #25
0
        public void OriginalInfoHash_IsSet()
        {
            // Arrange
            ParsedData = ValidSingleFileTorrentData;
            var expectedInfoHash = TorrentUtil.CalculateInfoHash(ParsedData.Get <BDictionary>("info"));

            // Act
            var parser  = new TorrentParser(BencodeParser);
            var torrent = parser.Parse((BencodeStream)null);

            // Assert
            torrent.OriginalInfoHash.Should().Be(expectedInfoHash);
        }
예제 #26
0
        public void Info_PieceLength_IsParsed(long pieceSize)
        {
            // Arrange
            ParsedData = ValidSingleFileTorrentData;
            var info = ParsedData.Get <BDictionary>(TorrentFields.Info);

            info[TorrentInfoFields.PieceLength] = (BNumber)pieceSize;

            // Act
            var parser  = new TorrentParser(BencodeParser);
            var torrent = parser.Parse((BencodeReader)null);

            // Assert
            torrent.PieceSize.Should().Be(pieceSize);
        }
예제 #27
0
        public void Info_Pieces_IsParsed(byte[] pieces)
        {
            // Arrange
            ParsedData = ValidSingleFileTorrentData;
            var info = ParsedData.Get <BDictionary>(TorrentFields.Info);

            info[TorrentInfoFields.Pieces] = new BString(pieces);

            // Act
            var parser  = new TorrentParser(BencodeParser);
            var torrent = parser.Parse((BencodeReader)null);

            // Assert
            torrent.Pieces.Should().Equal(pieces);
        }
예제 #28
0
        public void Info_Private_ShouldBeTrueOnlyIfValueIsOne(int value, bool expectedResult)
        {
            // Arrange
            ParsedData = ValidSingleFileTorrentData;
            var info = ParsedData.Get <BDictionary>(TorrentFields.Info);

            info[TorrentInfoFields.Private] = (BNumber)value;

            // Act
            var parser  = new TorrentParser(BencodeParser);
            var torrent = parser.Parse((BencodeReader)null);

            // Assert
            torrent.IsPrivate.Should().Be(expectedResult);
        }
예제 #29
0
        public void ExtraFields_IsParsed(string extraKey, string extraValue, string extraInfoKey, string extraInfoValue)
        {
            // Arrange
            ParsedData           = ValidSingleFileTorrentData;
            ParsedData[extraKey] = (BString)extraValue;
            ParsedData.Get <BDictionary>(TorrentFields.Info)[extraInfoKey] = (BString)extraInfoValue;

            // Act
            var parser  = new TorrentParser(BencodeParser);
            var torrent = parser.Parse((BencodeReader)null);

            // Assert
            torrent.ExtraFields.Should().Contain(extraKey, (BString)extraValue);
            torrent.ExtraFields.Get <BDictionary>(TorrentFields.Info).Should().Contain(extraInfoKey, (BString)extraInfoValue);
        }
예제 #30
0
        /// <summary>
        /// Checks the torrent data for required fields and throws an exception if any are missing or invalid.
        /// </summary>
        /// <param name="data">The torrent data.</param>
        /// <exception cref="InvalidTorrentException">The torrent data is missing required fields or otherwise invalid.</exception>
        protected void EnsureValidTorrentData(BDictionary data)
        {
            /*
             *  NOTE: The 'announce' field is technically required according to the specification,
             *        but is not really required for DHT and PEX.
             */

            if (!data.ContainsKey(TorrentFields.Info))
            {
                throw new InvalidTorrentException("Torrent is missing 'info'-dictionary.", TorrentFields.Info);
            }

            var info = data.Get <BDictionary>(TorrentFields.Info);

            var requiredFields = new List <string>
            {
                TorrentInfoFields.PieceLength,
                TorrentInfoFields.Pieces,
                TorrentInfoFields.Name
            };

            // Single-file torrents must have either the 'length' field or the 'files' field, but not both
            if (info.ContainsKey(TorrentInfoFields.Length) && info.ContainsKey(TorrentInfoFields.Files))
            {
                throw new InvalidTorrentException(
                          $"Torrent 'info'-dictionary cannot contain both '{TorrentInfoFields.Length}' and '{TorrentInfoFields.Files}'.");
            }

            if (!info.ContainsKey(TorrentInfoFields.Length))
            {
                requiredFields.Add(TorrentInfoFields.Files);
            }

            EnsureFields(requiredFields, info, "Torrent is missing required field in 'info'-dictionary.");

            if (info.ContainsKey(TorrentInfoFields.Files))
            {
                var filesData = info.Get <BList>(TorrentInfoFields.Files).AsType <BDictionary>();

                var requiredFileFields = new[]
                {
                    TorrentFilesFields.Length,
                    TorrentFilesFields.Path
                };

                EnsureFields(requiredFileFields, filesData, "Torrent is missing required field in 'info.files' dictionaries.");
            }
        }
예제 #31
0
        public void MergeWith_ExistingKeyOption_Skip_ListIsSkippedForExistingKeyOfSameType()
        {
            var dict1 = new BDictionary {{"key", new BList {"item1"}}};
            var dict2 = new BDictionary {{"key", new BList {"item2", "item3"}}};

            dict1.MergeWith(dict2, ExistingKeyAction.Skip);

            dict1.Should().HaveCount(1);
            dict1["key"].Should().BeOfType<BList>();
            dict1.Get<BList>("key").Should()
                .HaveCount(1)
                .And.ContainInOrder((BString) "item1");
        }
예제 #32
0
        public void MergeWith_ExistingKeyOption_Skip_DictionarySkippedForExistingKeyOfSameType()
        {
            var dict1 = new BDictionary {{"main", new BDictionary {{"key", "value"}}}};
            var dict2 = new BDictionary {{"main", new BDictionary {{"key2", "value2"}}}};

            dict1.MergeWith(dict2, ExistingKeyAction.Skip);

            dict1.Should().HaveCount(1);
            dict1.Get<BDictionary>("main").Should().HaveCount(1).And.ContainKey("key");
        }
예제 #33
0
        public void MergeWith_ExistingKeyOption_Merge_DictionaryMergedWithExistingKeyOfSameType()
        {
            var dict1 = new BDictionary {{"main", new BDictionary {{"key", "value"}}}};
            var dict2 = new BDictionary {{"main", new BDictionary {{"key2", "value2"}}}};

            dict1.MergeWith(dict2, ExistingKeyAction.Merge);

            dict1.Should().HaveCount(1);
            dict1.Get<BDictionary>("main").Should().HaveCount(2).And.ContainKeys("key", "key2");
        }
예제 #34
0
        public void MergeWith_DictionaryWithNewKeyIsAdded()
        {
            var dict1 = new BDictionary { { "main", new BDictionary { { "key", "value" } } } };
            var dict2 = new BDictionary { { "main2", new BDictionary { { "key2", "value2" } } } };

            dict1.MergeWith(dict2);

            dict1.Should().HaveCount(2);
            dict1.Get<BDictionary>("main").Should().HaveCount(1).And.ContainKeys("key");
            dict1.Get<BDictionary>("main2").Should().HaveCount(1).And.ContainKeys("key2");
        }
예제 #35
0
        public void MergeWith_DictionaryReplacesExistingKeyOfDifferentType()
        {
            var dict1 = new BDictionary {{"main", new BList {"item1"}}};
            var dict2 = new BDictionary {{"main", new BDictionary {{"key", "value"}}}};

            dict1.MergeWith(dict2);

            dict1.Should().HaveCount(1);
            dict1.Get<BDictionary>("main").Should().HaveCount(1).And.ContainKey("key");
        }
예제 #36
0
        public void MergeWith_ListReplacesExistingKeyOfDifferentType()
        {
            var dict1 = new BDictionary {{"key", "value"}};
            var dict2 = new BDictionary {{"key", new BList {"item1", "item2"}}};

            dict1.MergeWith(dict2);

            dict1.Should().HaveCount(1);
            dict1["key"].Should().BeOfType<BList>();
            dict1.Get<BList>("key").Should()
                .HaveCount(2)
                .And.ContainInOrder((BString) "item1", (BString) "item2");
        }