private static PeerInfo[] DecodePeers(BEncoding.List peerList) { var peerInfoList = new List <PeerInfo>(peerList.Count); foreach (var peer in peerList) { if (peer is BEncoding.Dictionary) { var peerDict = (peer as BEncoding.Dictionary); byte[] peerIDBytes; if (!peerDict.TryGetByteArray("peer id", out peerIDBytes) && !peerDict.TryGetByteArray("peer_id", out peerIDBytes)) { peerIDBytes = null; } string peerIP; long peerPort; if (peerDict.TryGetString("ip", out peerIP) && peerDict.TryGetInteger("port", out peerPort) && peerPort > 0 && peerPort <= ushort.MaxValue) { IPAddress ipAddress; if (IPAddress.TryParse(peerIP, out ipAddress)) { var endPoint = new IPEndPoint(ipAddress, (int)peerPort); if (peerIDBytes != null && peerIDBytes.Length == 20) { var peerID = new PeerID(peerIDBytes); peerInfoList.Add(new PeerInfo(peerID, endPoint)); } else { peerInfoList.Add(new PeerInfo(endPoint)); } } else { Log.LogError("[HTTP Tracker] Unable to parse peer IP: {0}", peerIP); } } } else if (peer is byte[]) { var peerBytes = peer as byte[]; var decodedPeers = DecodePeers(peerBytes); if (decodedPeers != null) { peerInfoList.AddRange(decodedPeers); } else { Log.LogError("[HTTP Tracker] Unable to decode peer information from {0} bytes of compact data.", peerBytes.Length); } } else { Log.LogError("[HTTP Tracker] Unable decode get peer information with invalid BEncode type: {0}", (peer != null ? peer.GetType().Name : "<null>")); } } return(peerInfoList.ToArray()); }
private BEncoding.Dictionary Save() { var torrentInfo = new BEncoding.Dictionary(); // Make sure that there is a piece size if (pieceSize == 0) { throw new InvalidOperationException("No piece size has been set yet."); } else if (!MathHelper.IsPowerOfTwo(pieceSize)) { throw new InvalidOperationException("The piece size must be a power of two."); } else if (files == null || files.Length == 0) { throw new InvalidOperationException("No files have been defined yet."); } else if (totalSize == 0L) { throw new InvalidOperationException("The total size of the torrent cannot be 0."); } int pieceCount = (int)((totalSize - 1) / pieceSize) + 1; if (pieceCount != pieceHashes.Length) { throw new InvalidOperationException(string.Format("The calculated number of pieces is {0} while there are {1} piece hashes.", pieceCount, pieceHashes.Length)); } if (announces != null && announces.Length > 0) { if (!string.IsNullOrEmpty(announces[0].Url)) { torrentInfo.Add("announce", announces[0].Url); } var trackerList = new BEncoding.List(); for (int i = 0; i < announces.Length; i++) { var urls = announces[i].Urls; if (urls == null || urls.Length == 0) { continue; } var urlList = new BEncoding.List(); for (int j = 0; j < urls.Length; j++) { if (!string.IsNullOrEmpty(urls[j])) { urlList.Add(urls[j]); } } if (urlList.Count > 0) { trackerList.Add(urlList); } } if (trackerList.Count > 0) { torrentInfo.Add("announce-list", trackerList); } } if (!string.IsNullOrEmpty(comment)) { torrentInfo.Add("comment", comment); } if (!string.IsNullOrEmpty(createdBy)) { torrentInfo.Add("created by", createdBy); } if (creationDate != DateTime.MinValue) { long creationDateTimestamp = TimeHelper.GetUnixTimestampFromDate(creationDate); torrentInfo.Add("creation date", creationDateTimestamp); } // Get the piece hash data byte[] pieceHashData = new byte[20 * pieceCount]; for (int i = 0; i < pieceCount; i++) { Buffer.BlockCopy(pieceHashes[i].Hash, 0, pieceHashData, (i * 20), 20); } var info = new BEncoding.Dictionary(); info.Add("piece length", pieceSize); info.Add("pieces", pieceHashData); info.Add("private", (isPrivate ? 1 : 0)); if (!string.IsNullOrEmpty(source)) { info.Add("source", source); } if (files != null) { if (files.Length == 1) { var fileItem = files[0]; info.Add("length", fileItem.Size); if (fileItem.MD5Hash != null && fileItem.MD5Hash.Length == 16) { string fileMD5HashHex = HexHelper.BytesToHex(fileItem.MD5Hash); info.Add("md5sum", fileMD5HashHex); } info.Add("name", GetFileName(fileItem.Path)); } else if (files.Length > 1) { info.Add("name", name ?? "Unnamed"); var fileList = new BEncoding.List(); for (int i = 0; i < files.Length; i++) { var fileItem = files[i]; var fileDictionary = new BEncoding.Dictionary(); fileDictionary.Add("length", fileItem.Size); if (fileItem.MD5Hash != null && fileItem.MD5Hash.Length == 16) { string fileMD5HashHex = HexHelper.BytesToHex(fileItem.MD5Hash); info.Add("md5sum", fileMD5HashHex); } string[] pathParts = fileItem.Path.Split(new char[] { '/' }); var pathList = new BEncoding.List(pathParts); fileDictionary.Add("path", pathList); fileList.Add(fileDictionary); } info.Add("files", fileList); } } infoHash = ComputeInfoHash(info); torrentInfo.Add("info", info); return(torrentInfo); }