public TorrentParserTests() { BencodeParser = Substitute.For<IBencodeParser>(); BencodeParser.Parse<BDictionary>((BencodeStream) null).ReturnsForAnyArgs(x => ParsedData); ValidSingleFileTorrentData = new BDictionary { [TorrentFields.Info] = new BDictionary { [TorrentInfoFields.Name] = (BString) "", [TorrentInfoFields.Pieces] = (BString) "", [TorrentInfoFields.PieceLength] = (BNumber) 0, [TorrentInfoFields.Length] = (BNumber) 0 }, }; ValidMultiFileTorrentData = new BDictionary { [TorrentFields.Info] = new BDictionary { [TorrentInfoFields.Name] = (BString) "", [TorrentInfoFields.Pieces] = (BString) "", [TorrentInfoFields.PieceLength] = (BNumber) 0, [TorrentInfoFields.Files] = new BList() }, }; }
/// <summary> /// Computes the "info_hash" of the provided torrent (BDictionary). /// </summary> /// <param name="torrent">The BDicionary containing the torrent file.</param> /// <returns>An InfoHash object with the SHA1 hash.</returns> public static InfoHash ComputeInfoHash(BDictionary torrent) { IBValue info = null; //looks for the "info" dictionary foreach (KeyValuePair<string, IBValue> item in torrent.Items) { if (item.Key == "info" && item.Value is BDictionary) { info = item.Value; break; } } //if found, then computes the SHA1 hash and returns it if (info != null) { //the info_hash is the sha1 hash of the bencoded "info" dictionary, so gets it string bencoded = info.ToBEncodedString(); List<byte> bytes = new List<byte>(bencoded.Length); //adds its bytes to a list to be used in the ComputeHash function foreach (char c in info.ToBEncodedString()) { bytes.Add((byte)c); } SHA1 sha1 = SHA1.Create(); return InfoHash.FromByteArray(sha1.ComputeHash(bytes.ToArray())); } //if the "info" dictionary is not found, then returns an empty InfoHash to avoid exceptions... return InfoHash.FromByteArray(new byte[] { }); }
public void CanEncode_Complex() { var bdict = new BDictionary { {"spam", "egg"}, { "A List", new BList { "foo", "bar", 123, new BDictionary { {"more spam", "more eggs"} } } }, { "foobar", new BDictionary { {"numbers", new BList {1, 2, 3}} } } }; var bencode = bdict.EncodeAsString(); bencode.Should() .Be("d6:A Listl3:foo3:bari123ed9:more spam9:more eggsee6:foobard7:numbersli1ei2ei3eee4:spam3:egge"); }
private static BDictionary ReadDictionary(BinaryReader binaryReader) { Contract.Requires(binaryReader != null); int i = binaryReader.ReadByte(); if (i != 'd') { throw Error(); } BDictionary dict = new BDictionary(); try { for (int c = binaryReader.PeekChar(); ; c = binaryReader.PeekChar()) { if (c == -1) throw Error(); if (c == 'e') { binaryReader.ReadByte(); break; } BString k = ReadString(binaryReader); IBElement v = ReadElement(binaryReader); dict.Add(k, v); } } catch (BencodingException) { throw; } catch (Exception e) { throw Error(e); } return dict; }
public void Encode_Complex() { var bdict = new BDictionary { {"spam", "egg"}, { "A List", new BList { "foo", "bar", 123, new BDictionary { {"more spam", "more eggs"} } } }, { "foobar", new BDictionary { {"numbers", new BList {1, 2, 3}} } } }; // Keys should be sorted in lexical order var expected = "d6:A Listl3:foo3:bari123ed9:more spam9:more eggsee6:foobard7:numbersli1ei2ei3eee4:spam3:egge"; var actual = bdict.Encode(); Assert.AreEqual(expected, actual); }
private void WriteDictionary(int indentLevel, BDictionary dict) { Console.WriteLine("{0}Dict:", GetIndentSpaces(indentLevel)); foreach (var kvPair in dict.Value) { WriteByteString(indentLevel + 1, kvPair.Key); WriteObject(indentLevel + 2, kvPair.Value); } }
public BList GetTorrentFiles() { List<IBObject> files = new List<IBObject>(); foreach (TorrentFileStruct torrentFile in torrentFiles) { List<BByteString> fileInfoName = new List<BByteString>(); foreach (string subPath in torrentFile.Path.Split('\\')) { fileInfoName.Add(new BByteString(subPath)); } BDictionary infoFile = new BDictionary(); infoFile.Value.Add(new BByteString("path"), new BList() { Value = fileInfoName.ToArray() }); infoFile.Value.Add(new BByteString("length"), new BInteger(torrentFile.Length)); files.Add(infoFile); } return new BList() { Value = files.ToArray() }; }
public void CalculateInfoHash_SimpleInfoDictionary() { var info = new BDictionary { ["key"] = (BString) "value", ["list"] = new BList {1, 2, 3}, ["number"] = (BNumber)42, ["dictionary"] = new BDictionary { ["key"] = (BString) "value" } }; var hash = TorrentUtil.CalculateInfoHash(info); info.EncodeAsString().Should().Be("d10:dictionaryd3:key5:valuee3:key5:value4:listli1ei2ei3ee6:numberi42ee"); hash.Should().Be("8715E7488A8964C6383E09A87287321FE6CBCC07"); }
public void Encode_KeyAreSortedInLexicalOrder() { var bdict = new BDictionary { {"number", 747}, {"foobar", "Hello World!"}, {"key", "value"} }; var bencode = bdict.EncodeAsString(); bencode.Should().Be("d6:foobar12:Hello World!3:key5:value6:numberi747ee"); }
public DHTErrorMessage(MessageType type, QueryType queryType, BDictionary data) : base(type, queryType, data) { }
public void SequenceEqual_WithKeysAddedInSameOrder_AreEqual() { var bdict1 = new BDictionary { {"foobar", "Hello World!"}, {"number", 747}, {"key", "value"} }; var bdict2 = new BDictionary { {"foobar", "Hello World!"}, {"number", 747}, {"key", "value"} }; bdict1.SequenceEqual(bdict2).Should().BeTrue(); }
public void CanEncode_EmptyDictionary() { var bdict = new BDictionary(); var bencode = bdict.EncodeAsString(); bencode.Should().Be("de"); }
public Fastresume(BDictionary bDictionary) : base(bDictionary) { }
/// <summary> /// Calculates the hash of the 'info'-dictionary. /// The info hash is a 20-byte SHA1 hash of the 'info'-dictionary of the torrent /// used to uniquely identify it and it's contents. /// /// <para>Example: 6D60711ECF005C1147D8973A67F31A11454AB3F5</para> /// </summary> /// <param name="info">The 'info'-dictionary of a torrent.</param> /// <returns>A string representation of the 20-byte SHA1 hash without dashes.</returns> public static string CalculateInfoHash(BDictionary info) { var hashBytes = CalculateInfoHashBytes(info); return(BitConverter.ToString(hashBytes).Replace("-", "")); }
async Task HandleVar_ExecuteOne(string id, BDictionary msg) => await HandleVar_Execute_Internal(id, msg, expectOne : true);
void singleFileTorrent(BDictionary info, FileInfo file) { info["name"] = new BString(file.Name); info["length"] = new BInteger(file.Length); }
async Task HandleVar_Execute_Internal(string id, BDictionary msg, bool expectOne = false, bool rawResults = false) { if (!msg.TryGetValue("args", out var beArgs) || !(beArgs is BString beArgsStr)) { await SendException(id, $"Missing required \"args\" argument."); return; } IReadOnlyDictionary <string, JToken> argMap; try { argMap = JsonConvert.DeserializeObject <IList <IReadOnlyDictionary <string, JToken> > >(beArgsStr.ToString()).First(); } catch (Exception ex) { await SendException(id, $"Couldn't deserialize json payload. Expected a map. Error: {ex.Message}"); return; } if (!argMap.TryGetNonBlankString("connection-string", out var connStr)) { await SendException(id, $"Missing required \"connection-string\" argument."); return; } if (!argMap.TryGetNonBlankString("command-text", out var commandText)) { await SendException(id, $"Missing required \"command-text\" argument."); return; } try { using (var conn = new SqlConnection(connStr)) using (var cmd = conn.CreateCommand()) { await conn.OpenAsync(); cmd.CommandText = commandText; if (argMap.TryGetValue("command-type", out JToken commandTypeTok) && commandTypeTok.Type != JTokenType.Null) { if (commandTypeTok.Type != JTokenType.String) { await SendException(id, $"Expected string. Failing key: \"$.command-type\""); return; } var commandType = commandTypeTok.Value <string>(); switch (commandType) { case "stored-procedure": cmd.CommandType = System.Data.CommandType.StoredProcedure; break; case "text": break; // This is the default default: await SendException(id, $"Expected \"stored-procedure\" | \"text\". Failing key: \"$.command-type\""); return; } } if (argMap.TryGetValue("parameters", out JToken paramTok) && paramTok is JObject paramObj) { foreach (var item in paramObj) { if (!(item.Value is JValue v)) { await SendException(id, $"Can only accept simple values (integers, strings, etc) for parameters. Failing key: \"$.parameters.{item.Key}\""); return; } cmd.Parameters.AddWithValue(item.Key, v.Value); } } var results = new List <object>(); bool multiResultSet; argMap.TryGetBool("multi-rs", out multiResultSet); // same key as next.jdbc using (var rdr = await cmd.ExecuteReaderAsync()) { do { var fieldCount = rdr.FieldCount; var rs = new ResultSet { columns = Enumerable.Range(0, fieldCount) .Select(i => rdr.GetName(i)) .ToArray() }; var isJson = rs.columns.Length == 1 && rs.columns[0] == "JSON_F52E2B61-18A1-11d1-B105-00805F49916B"; if (isJson) { var sb = new StringBuilder(); while (rdr.Read()) { sb.Append(rdr.GetString(0)); } if (expectOne || !multiResultSet) { await SendResult(id, sb.ToString(), isJson : true); return; } else { // @PERF - Think of a way to eliminate deserialize -> serialize for this case var obj = ParseJson(sb.ToString()); results.Add(obj); } } else { var rows = rs.rows = new List <object[]>(); while (rdr.Read()) { var row = new object[fieldCount]; for (int i = 0; i < fieldCount; i++) { rdr.GetValues(row); } rows.Add(row); } if (expectOne) { if (rows.Count > 0) { await SendResult(id, ResultSet2DictArray(rs)[0]); } else { await SendResult(id, null); } return; } results.Add(rawResults ? (object)rs : ResultSet2DictArray(rs)); } } while (rdr.NextResult() && multiResultSet); } object result = null; if (rawResults || multiResultSet) { result = results; } else if (results.Count > 0) { result = results[0]; } await SendResult(id, result); } } catch (Exception ex) { await SendException(id, ex.Message); } }
async Task HandleVar_Execute(string id, BDictionary msg) => await HandleVar_Execute_Internal(id, msg);
public static TorrentInfo Parse(BDictionary dictionary) { Contract.Requires(dictionary != null); if (dictionary == null) { throw new ArgumentNullException(nameof(dictionary)); } var torrent = new TorrentInfo(); TorrentFileInfo singleFile = new TorrentFileInfo(); bool isSingleFile = false; foreach (var item in dictionary) { if (item.Key == null) { continue; } if (item.Key.Value == "announce") { if (item.Value != null) { torrent.Announce = item.Value.ToString(); } } else if (item.Key.Value == "created by") { if (item.Value != null) { torrent.CreatedBy = item.Value.ToString(); } } else if (item.Key.Value == "creation date") { if (item.Value is BInteger integer) { torrent.CreationDate = new DateTime(1970, 1, 1).AddSeconds(integer.Value); } } else if (item.Key.Value == "encoding") { if (item.Value != null) { torrent.Encoding = item.Value.ToString(); } } else if (item.Key.Value == "info") { if (item.Value is BDictionary dict) { ParseInfo(torrent, singleFile, ref isSingleFile, dict); } } } if (isSingleFile) { singleFile.Path?.Add(torrent.Name); torrent.Files.Add(singleFile); } return(torrent); }
private static void ParseInfo(TorrentInfo torrent, TorrentFileInfo singleFile, ref bool isSingleFile, BDictionary dictionary) { Contract.Requires(torrent != null); Contract.Requires(singleFile != null); Contract.Requires(dictionary != null); foreach (var info in dictionary) { if (info.Key == null) { continue; } if (info.Key.Value == "name") { if (info.Value != null) { torrent.Name = info.Value.ToString(); } } else if (info.Key.Value == "piece length") { BInteger integer = info.Value as BInteger; if (integer != null) { torrent.PieceLength = integer.Value; } } else if (info.Key.Value == "pieces") { if (info.Value != null) { torrent.Pieces = info.Value.ToString(); } } else if (info.Key.Value == "private") { BInteger integer = info.Value as BInteger; if (integer != null) { torrent.Private = integer.Value != 0; } } else if (info.Key.Value == "files") { if (info.Value is BList files) { foreach (var file in files) { if (file is BDictionary dict) { torrent.Files.Add(TorrentFileInfo.Parse(dict)); } } } } else if (info.Key.Value == "file-duration") { isSingleFile = true; if (info.Value is BList items) { foreach (var item in items) { BInteger integer = item as BInteger; if (integer != null) { singleFile.Duration.Add(integer.Value); } } } } else if (info.Key.Value == "file-media") { isSingleFile = true; if (info.Value is BList items) { foreach (var item in items) { BInteger integer = item as BInteger; if (integer != null) { singleFile.Media.Add(integer.Value); } } } } else if (info.Key.Value == "profiles") { isSingleFile = true; if (info.Value is BList items) { foreach (var item in items) { if (item is BDictionary dictItems) { TorrentFileProfileCollection profiles = new TorrentFileProfileCollection(); profiles.AddRange(dictItems.Select(dictItem => new TorrentFileProfile { Name = dictItem.Key.ToString(), Value = dictItem.Value.ToString() })); singleFile.Profiles.Add(profiles); } } } } } }
public void FillFromInfo(BDictionary bInfo) { if (bitSwarm.OptionsClone.FolderComplete == null) { bitSwarm.StopWithError("[CRITICAL] Folder Complete cannot be empty"); } bool isMultiFile = (BList)bInfo["files"] == null ? false : true; file.pieces = GetHashesFromInfo(bInfo); file.pieceLength = (BNumber)bInfo["piece length"]; data.filesIncludes = new List <string>(); Partfiles.Options opt = new Partfiles.Options(); opt.AutoCreate = true; long startPos = 0; if (isMultiFile) { file.paths = GetPathsFromInfo(bInfo); data.files = new Partfile[file.paths.Count]; file.lengths = GetFileLengthsFromInfo(bInfo, out long tmpTotalSize); data.totalSize = tmpTotalSize; data.folder = Path.Combine(bitSwarm.OptionsClone.FolderComplete, Utils.GetValidPathName(file.name)); data.folderTemp = Path.Combine(bitSwarm.OptionsClone.FolderIncomplete, Utils.GetValidPathName(file.name)); if (Directory.Exists(data.folder)) { bitSwarm.StopWithError($"Torrent folder already exists! {data.folder}"); } if (Directory.Exists(data.folderTemp)) { Directory.Delete(data.folderTemp, true); } opt.Folder = data.folder; opt.PartFolder = data.folderTemp; for (int i = 0; i < file.paths.Count; i++) { data.files[i] = new Partfile(file.paths[i], file.pieceLength, file.lengths[i], opt); data.filesIncludes.Add(file.paths[i]); startPos += file.lengths[i]; } } else { file.length = (BNumber)bInfo["length"]; data.totalSize = file.length; data.files = new Partfile[1]; string filePath = Path.Combine(bitSwarm.OptionsClone.FolderComplete, Utils.GetValidFileName(file.name)); if (File.Exists(filePath)) { bitSwarm.StopWithError($"Torrent file already exists! {filePath}"); } opt.Folder = bitSwarm.OptionsClone.FolderComplete; opt.PartFolder = bitSwarm.OptionsClone.FolderIncomplete; opt.PartOverwrite = true; data.files[0] = new Partfile(Utils.GetValidFileName(file.name), file.pieceLength, file.length, opt); file.paths = new List <string>() { file.name }; file.lengths = new List <long>() { file.length }; data.filesIncludes.Add(file.name); } data.pieces = file.pieces.Count; data.pieceSize = file.pieceLength; data.pieceLastSize = (int)(data.totalSize % data.pieceSize); // NOTE: it can be 0, it should be equals with pieceSize in case of totalSize % pieceSize = 0 data.blockSize = Math.Min(Peer.MAX_DATA_SIZE, data.pieceSize); data.blocks = ((data.pieceSize - 1) / data.blockSize) + 1; data.blockLastSize = data.pieceLastSize % data.blockSize == 0 ? data.blockSize : data.pieceLastSize % data.blockSize; data.blockLastSize2 = data.pieceSize % data.blockSize == 0 ? data.blockSize : data.pieceSize % data.blockSize; data.blocksLastPiece = ((data.pieceLastSize - 1) / data.blockSize) + 1; data.progress = new Bitfield(data.pieces); data.requests = new Bitfield(data.pieces); data.progressPrev = new Bitfield(data.pieces); data.pieceProgress = new Dictionary <int, TorrentData.PieceProgress>(); SaveSession(); }
// BEncode public static object GetFromBDic(BDictionary dic, string[] path) { return(GetFromBDicRec(dic, path, 0)); }
async Task HandleVar_ExecuteRaw(string id, BDictionary msg) => await HandleVar_Execute_Internal(id, msg, rawResults : true);
public MessageEventArgs(IPEndPoint peerEndPoint, byte[] nodeId, BDictionary data) : base(peerEndPoint, nodeId) { Data = data; }
/// <summary> /// Creates a torrent and populates the <see cref="OriginalInfoHash"/> and <see cref="OriginalInfoHashBytes"/> /// properties from the provided <see cref="BDictionary"/>. /// </summary> /// <param name="originalInfoDictionary"></param> internal Torrent(BDictionary originalInfoDictionary) { OriginalInfoHashBytes = TorrentUtil.CalculateInfoHashBytes(originalInfoDictionary); OriginalInfoHash = TorrentUtil.BytesToHexString(OriginalInfoHashBytes); }
void createTorrent(TorrentCreationViewModel vm) { /* info: a dictionary that describes the file(s) of the torrent. There are two possible forms: one for the case of a 'single-file' torrent with no directory structure, and one for the case of a 'multi-file' torrent (see below for details) announce: The announce URL of the tracker (string) announce-list: (optional) this is an extention to the official specification, offering backwards-compatibility. (list of lists of strings). The official request for a specification change is here. creation date: (optional) the creation time of the torrent, in standard UNIX epoch format (integer, seconds since 1-Jan-1970 00:00:00 UTC) comment: (optional) free-form textual comments of the author (string) created by: (optional) name and version of the program used to create the .torrent (string) encoding: (optional) the string encoding format used to generate the pieces part of the info dictionary in the .torrent metafile (string) */ BDictionary info = new BDictionary(); info["pieces"] = new BString(buildPiecesHash(vm.Media)); info["piece length"] = new BInteger(pieceLength); info["private"] = new BInteger(vm.IsPrivate ? 1 : 0); if (vm.Media.Count == 1) { singleFileTorrent(info, new FileInfo(vm.Media.ElementAt(0).Location)); } else { List<FileInfo> fileInfo = new List<FileInfo>(); foreach (MediaFileItem item in vm.Media) { fileInfo.Add(new FileInfo(item.Location)); } multiFileTorrent(info, vm, fileInfo); } BDictionary metaInfo = new BDictionary(); metaInfo["info"] = info; metaInfo["announce"] = new BString(vm.AnnounceURL); metaInfo["creation date"] = new BInteger((long)(DateTime.Now - new DateTime(1970, 1, 1)).TotalSeconds); metaInfo["created by"] = new BString(createdBy); if (!String.IsNullOrEmpty(vm.Comment) && !String.IsNullOrWhiteSpace(vm.Comment) && vm.IsCommentEnabled) { metaInfo["comment"] = new BString(vm.Comment); } if (!String.IsNullOrEmpty(encoding) && !String.IsNullOrWhiteSpace(encoding) && vm.IsCommentEnabled) { metaInfo["encoding"] = new BString(encoding); } String torrentName = String.IsNullOrEmpty(vm.TorrentName) ? Path.GetFileNameWithoutExtension(vm.Media.ElementAt(0).Location) : vm.TorrentName; String torrentFullName = vm.OutputPath + "\\" + torrentName + ".torrent"; if (CancellationToken.IsCancellationRequested) return; FileStream outputTorrent = null; try { outputTorrent = new FileStream(torrentFullName, FileMode.CreateNew); BinaryWriter bw = new BinaryWriter(outputTorrent); foreach (char c in metaInfo.ToBencodedString()) { bw.Write((byte)c); } InfoMessages.Add("Created torrent file: " + torrentFullName); } finally { if (outputTorrent != null) { outputTorrent.Close(); } } }
static void HandleMessage(BDictionary message, TcpClient client) { var opValue = message["op"]; var opString = opValue as BString; if (opString != null) { var session = GetSession(message); switch (opString.ToString()) { case "clone": var newSession = CloneSession(session); SendMessage( new BDictionary { { "id", message["id"] }, { "status", new BList { "done" } }, { "new-session", newSession.ToString() } }, client); break; case "describe": // TODO include arcadia version var clojureVersion = (IPersistentMap)RT.var("clojure.core", "*clojure-version*").deref(); var clojureMajor = (int)clojureVersion.valAt(Keyword.intern("major")); var clojureMinor = (int)clojureVersion.valAt(Keyword.intern("minor")); var clojureIncremental = (int)clojureVersion.valAt(Keyword.intern("incremental")); var clojureQualifier = (string)clojureVersion.valAt(Keyword.intern("qualifier")); SendMessage( new BDictionary { { "id", message["id"] }, { "session", session.ToString() }, { "status", new BList { "done" } }, { "ops", new BDictionary { { "eval", 1 }, { "load-file", 1 }, { "describe", 1 }, { "clone", 1 }, { "info", 1 }, } }, { "versions", new BDictionary { { "clojure", new BDictionary { { "major", clojureMajor }, { "minor", clojureMinor }, { "incremental", clojureIncremental }, { "qualifier", clojureQualifier } } }, { "nrepl", new BDictionary { { "major", 0 }, { "minor", 2 }, { "incremental", 3 } } } } } }, client); break; case "eval": var fn = new EvalFn(message, client); addCallbackVar.invoke(fn); break; case "load-file": message["code"] = new BString("(do " + message["file"].ToString() + " )"); var loadFn = new EvalFn(message, client); addCallbackVar.invoke(loadFn); break; case "info": var symbolMetadata = (IPersistentMap)metaVar.invoke(nsResolveVar.invoke( findNsVar.invoke(symbolVar.invoke(message["ns"].ToString())), symbolVar.invoke(message["symbol"].ToString()))); if (symbolMetadata != null) { var resultMessage = new BDictionary { { "id", message["id"] }, { "session", session.ToString() }, { "status", new BList { "done" } } }; foreach (var entry in symbolMetadata) { if (entry.val() != null) { resultMessage[entry.key().ToString().Substring(1)] = new BString(entry.val().ToString()); } } SendMessage(resultMessage, client); } else { SendMessage( new BDictionary { { "id", message["id"] }, { "session", session.ToString() }, { "status", new BList { "done", "no-info" } } }, client); } break; default: SendMessage( new BDictionary { { "id", message["id"] }, { "session", session.ToString() }, { "status", new BList { "done", "error", "unknown-op" } } }, client); break; } } }
/// <summary> /// Private method that parses and returns the dictionary in the current position of the stream. /// </summary> /// <param name="br">The BinaryReader with the data to parse.</param> /// <returns>The dictionary parsed.</returns> /// <remarks>If the current position does not contain data similar to "dBencoded_stringBencoded_elemente", which is a bencoded dictionary, an exception will be thrown.</remarks> private static BDictionary ParseDictionary(BinaryReader br) { StringBuilder buffer = new StringBuilder(1024); char c = (char)br.ReadByte(); if (c != 'd') throw new InvalidCharacterException(c, "'d'"); BDictionary dictionary = new BDictionary(); do { string key = ParseString(br); IBValue value = Parse(br); dictionary.Add(key, value); } while ((char)br.PeekChar() != 'e'); br.ReadByte(); //skips the 'e' char return dictionary; }
public static bool TryParse(BDictionary message, out GetPeersResponse response) { response = null; if (message.TryGetValue("t", out BString transactionId) && transactionId.Length > 0 && message.TryGetValue("a", out BDictionary arguments) && arguments.TryGetValue("id", out BString nodeId) && nodeId.Length == NodeID.Size && arguments.TryGetValue("token", out BString token) && token.Length > 0) { if (arguments.TryGetValue("values", out BList values)) { PeerContact[] peers = new PeerContact[values.Count]; for (int i = 0; i < peers.Length; i++) { BObject value = values[i]; if (value is BString peer) { if (peer.Length == IPv4PeerContact.CompactInfoSize) { peers[i] = new IPv4PeerContact(peer); } else if (peer.Length == IPv6PeerContact.CompactInfoSize) { peers[i] = new IPv6PeerContact(peer); } else { return(false); } } else { return(false); } } response = new GetPeersResponse(new TransactionID(transactionId), new NodeID(nodeId), new PeerToken(token), peers); } else { IPv4Node[] nodes = null; IPv6Node[] nodes6 = null; if (arguments.TryGetValue("nodes", out BString nodeBytes)) { if (!IPv4Node.TryParseCompactNodeInfos(nodeBytes.Bytes, out nodes)) { return(false); } } if (arguments.TryGetValue("nodes6", out BString node6Bytes)) { if (!IPv6Node.TryParseCompactNodeInfos(nodeBytes.Bytes, out nodes6)) { return(false); } } if (nodes != null) { if (nodes6 != null) { response = new GetPeersResponse(new TransactionID(transactionId), new NodeID(nodeId), new PeerToken(token), nodes, nodes6); } else { response = new GetPeersResponse(new TransactionID(transactionId), new NodeID(nodeId), new PeerToken(token), nodes); } } else if (nodes6 != null) { response = new GetPeersResponse(new TransactionID(transactionId), new NodeID(nodeId), new PeerToken(token), nodes6); } } } return(response != null); }
public void Add_NullValue_ThrowsArgumentNullException() { var dict = new BDictionary(); Action action = () => dict.Add("key", null); action.ShouldThrow<ArgumentNullException>(); }
private static void GetTorrentFileList(IList <Model.TorrentFileName> filelist, BDictionary file) { // File size in bytes (BNumber has implicit conversion to int and long) long size = (BNumber)file["length"]; // List of all parts of the file path. 'dir1/dir2/file.ext' => dir1, dir2 and file.ext BList path = (BList)file["path"]; string fullpath = String.Join("\\", path); // Last element is the file name BString fileName = (BString)path.Last(); // Converts fileName (BString = bytes) to a string string fileNameString = fileName.ToString(Encoding.UTF8); var tf = new Model.TorrentFileName(); tf.Name = fileNameString; tf.Size = size; tf.Path = fullpath; tf.IsWanted = true; filelist.Add(tf); }
protected override BDictionary <int, int> CopySection(BDictionary <int, int> blist, int start, int subcount) { return(blist.CopySection(start, subcount)); }
public EvalFn(BDictionary request, TcpClient client) { _request = request; _client = client; }
public void CanEncode_Simple() { var bdict = new BDictionary { {"foobar", "Hello World!"}, {"number", 747} }; var bencode = bdict.EncodeAsString(); bencode.Should().Be("d6:foobar12:Hello World!6:numberi747ee"); }
static void HandleMessage(BDictionary message, TcpClient client) { var opValue = message["op"]; var opString = opValue as BString; var autoCompletionSupportEnabled = RT.booleanCast(((IPersistentMap)configVar.invoke()).valAt(Keyword.intern("nrepl-auto-completion"))); if (opString != null) { var session = GetSession(message); switch (opString.ToString()) { case "clone": var newSession = CloneSession(session); SendMessage( new BDictionary { { "id", message["id"] }, { "status", new BList { "done" } }, { "new-session", newSession.ToString() } }, client); break; case "describe": // TODO include arcadia version var clojureVersion = (IPersistentMap)RT.var("clojure.core", "*clojure-version*").deref(); var clojureMajor = (int)clojureVersion.valAt(Keyword.intern("major")); var clojureMinor = (int)clojureVersion.valAt(Keyword.intern("minor")); var clojureIncremental = (int)clojureVersion.valAt(Keyword.intern("incremental")); var clojureQualifier = (string)clojureVersion.valAt(Keyword.intern("qualifier")); var supportedOps = new BDictionary { { "eval", 1 }, { "load-file", 1 }, { "describe", 1 }, { "clone", 1 }, { "info", 1 }, { "eldoc", 1 }, { "classpath", 1 }, }; // Debug.Log("Autocomplete support is enabled?: " + autoCompletionSupportEnabled); if (autoCompletionSupportEnabled) { supportedOps.Add("complete", 1); } SendMessage( new BDictionary { { "id", message["id"] }, { "session", session.ToString() }, { "status", new BList { "done" } }, { "ops", supportedOps }, { "versions", new BDictionary { { "clojure", new BDictionary { { "major", clojureMajor }, { "minor", clojureMinor }, { "incremental", clojureIncremental }, { "qualifier", clojureQualifier } } }, { "nrepl", new BDictionary { { "major", 0 }, { "minor", 2 }, { "incremental", 3 } } } } } }, client); break; case "eval": var fn = new EvalFn(message, client); fn.invoke(); break; case "load-file": message["code"] = new BString("(do " + message["file"].ToString() + " )"); var loadFn = new EvalFn(message, client); loadFn.invoke(); break; case "eldoc": case "info": String symbolStr = message["symbol"].ToString(); // Editors like Calva that support doc-on-hover sometimes will ask about empty strings or spaces if (symbolStr == "" || symbolStr == null || symbolStr == " ") { break; } IPersistentMap symbolMetadata = null; try { symbolMetadata = (IPersistentMap)metaVar.invoke(nsResolveVar.invoke( findNsVar.invoke(symbolVar.invoke(message["ns"].ToString())), symbolVar.invoke(symbolStr))); } catch (TypeNotFoundException) { // We'll just ignore this call if the type cannot be found. This happens sometimes. // TODO: One particular case when this happens is when querying info for a namespace. // That case should be handled separately (e.g., via `find-ns`?) } if (symbolMetadata != null) { var resultMessage = new BDictionary { { "id", message["id"] }, { "session", session.ToString() }, { "status", new BList { "done" } } }; foreach (var entry in symbolMetadata) { if (entry.val() != null) { String keyStr = entry.key().ToString().Substring(1); String keyVal = entry.val().ToString(); if (keyStr == "arglists") { keyStr = "arglists-str"; } if (keyStr == "forms") { keyStr = "forms-str"; } resultMessage[keyStr] = new BString(keyVal); } } SendMessage(resultMessage, client); } else { SendMessage( new BDictionary { { "id", message["id"] }, { "session", session.ToString() }, { "status", new BList { "done", "no-info" } } }, client); } break; case "complete": // When autoCompletionSupportEnabled is false, we don't advertise auto-completion support. // some editors seem to ignore this and request anyway, so we return an unknown op message. if (!autoCompletionSupportEnabled) { SendMessage( new BDictionary { { "id", message["id"] }, { "session", session.ToString() }, { "status", new BList { "done", "error", "unknown-op" } } }, client); break; } Namespace ns = Namespace.find(Symbol.create(message["ns"].ToString())); var sessionBindings = _sessions[session]; var completeBindings = sessionBindings; if (ns != null) { completeBindings = completeBindings.assoc(RT.CurrentNSVar, ns); } // Make sure to eval this in the right namespace Var.pushThreadBindings(completeBindings); BList completions = (BList)completeVar.invoke(message["symbol"].ToString()); Var.popThreadBindings(); SendMessage(new BDictionary { { "id", message["id"] }, { "session", session.ToString() }, { "status", new BList { "done" } }, { "completions", completions } }, client); break; case "classpath": BList classpath = new BList(); foreach (String p in Environment.GetEnvironmentVariable("CLOJURE_LOAD_PATH").Split(System.IO.Path.PathSeparator)) { if (p != "") { classpath.Add(Path.GetFullPath(p)); } } SendMessage(new BDictionary { { "id", message["id"] }, { "session", session.ToString() }, { "status", new BList { "done" } }, { "classpath", classpath }, }, client); break; default: SendMessage( new BDictionary { { "id", message["id"] }, { "session", session.ToString() }, { "status", new BList { "done", "error", "unknown-op" } } }, client); break; } } }
public void SaveTorrentFile() { if (!TorrentPrepared) { return; } BDictionary torrent = new BDictionary(); torrent.Value.Add(new BByteString("announce"), torrentSaved.GetAnnounce()); torrent.Value.Add(new BByteString("info"), torrentSaved.GetInfo()); torrent.Value.Add(new BByteString("creation date"), new BInteger(TimeUnix())); using (FileStream outputFileStream = new FileStream(torrentSaved.FileName, FileMode.Create, FileAccess.Write)) { BObjectTransform objTransform = new BObjectTransform(); objTransform.EncodeObject(torrent, outputFileStream); } Console.WriteLine("\n{0} [{1}]\n", messages.GetMessage("TorrentCreated"), torrentSaved.FileName); }
/// <summary> /// Calculates the hash of the 'info'-dictionary. /// The info hash is a 20-byte SHA1 hash of the 'info'-dictionary of the torrent /// used to uniquely identify it and it's contents. /// /// <para>Example: 6D60711ECF005C1147D8973A67F31A11454AB3F5</para> /// </summary> /// <param name="info">The 'info'-dictionary of a torrent.</param> /// <returns>A string representation of the 20-byte SHA1 hash without dashes.</returns> public static string CalculateInfoHash(BDictionary info) { var hashBytes = CalculateInfoHashBytes(info); return(BytesToHexString(hashBytes)); }
public BDictionary GetInfo() { BDictionary info = new BDictionary(); info.Value.Add(new BByteString("files"), Info.GetTorrentFiles()); info.Value.Add(new BByteString("pieces"), Info.GetPieces()); info.Value.Add(new BByteString("name"), Info.GetName()); info.Value.Add(new BByteString("piece length"), Info.GetPieceLength()); info.Value.Add(new BByteString("private"), Info.GetPrivateTorrent()); info.Value.Add(new BByteString("source"), new BByteString(String.Format("{0} {1}", typeof(Torrent).Assembly.GetName().Name, typeof(Torrent).Assembly.GetName().Version))); return info; }
public DHTMessage(MessageType type, QueryType queryType, BDictionary data) { fType = type; fQueryType = queryType; fData = data; }
static void HandleMessage(BDictionary message, TcpClient client) { var opValue = message["op"]; var opString = opValue as BString; if (opString != null) { var session = GetSession(message); switch (opString.ToString()) { case "clone": var newSession = CloneSession(session); SendMessage( new BDictionary { { "id", message["id"] }, { "status", new BList { "done" } }, { "new-session", newSession.ToString() } }, client); break; case "describe": // TODO include arcadia version var clojureVersion = (IPersistentMap)RT.var("clojure.core", "*clojure-version*").deref(); var clojureMajor = (int)clojureVersion.valAt(Keyword.intern("major")); var clojureMinor = (int)clojureVersion.valAt(Keyword.intern("minor")); var clojureIncremental = (int)clojureVersion.valAt(Keyword.intern("incremental")); var clojureQualifier = (string)clojureVersion.valAt(Keyword.intern("qualifier")); SendMessage( new BDictionary { { "id", message["id"] }, { "session", session.ToString() }, { "status", new BList { "done" } }, { "ops", new BDictionary { { "eval", 1 }, { "describe", 1 }, { "clone", 1 }, } }, { "versions", new BDictionary { { "clojure", new BDictionary { { "major", clojureMajor }, { "minor", clojureMinor }, { "incremental", clojureIncremental }, { "qualifier", clojureQualifier } } }, { "nrepl", new BDictionary { { "major", 0 }, { "minor", 2 }, { "incremental", 3 } } } } } }, client); break; case "eval": var fn = new EvalFn(message, client); addCallbackVar.invoke(fn); break; default: SendMessage( new BDictionary { { "id", message["id"] }, { "session", session.ToString() }, { "status", new BList { "done", "error", "unknown-op" } } }, client); break; } } }
public override BDictionary <int, int> RemoveSection(BDictionary <int, int> blist, int start, int subcount) { return(blist.RemoveSection(start, subcount)); }
public static void SendMessage(BDictionary message, TcpClient client) { var bytes = message.EncodeAsBytes(); client.GetStream().Write(bytes, 0, bytes.Length); }
private void SendData(IPEndPoint endPoint, BDictionary data) { fDHTClient.Send(endPoint, data); fTCPClient.Send(endPoint, data.EncodeAsBytes()); }
public DHTResponseMessage(MessageType type, QueryType queryType, BDictionary data) : base(type, queryType, data) { }
public void MergeWith_ListWithNewKeyIsAdded() { var list = new BList {1, 2, 3}; var dict1 = new BDictionary {{"key", 1}}; var dict2 = new BDictionary {{"another key", list}}; dict1.MergeWith(dict2); dict1.Should().HaveCount(2); dict1["key"].Should().Be((BNumber) 1); dict1["another key"].Should().Be(list); }
protected DHTMessage(BDictionary data) { fData = data; }
public void MergeWith_NumberReplacesExistingKey() { var dict1 = new BDictionary {{"key", 1}}; var dict2 = new BDictionary {{"key", 42}}; dict1.MergeWith(dict2); dict1.Should().HaveCount(1); dict1["key"].Should().Be((BNumber) 42); }
public void EncodeObject_BDictionary_Positive() { string expectedOutput = "d3:one9:value_one3:twoi1ee"; MemoryStream outputBuffer = new MemoryStream(64); // Create input test data BDictionary data = new BDictionary(); data.Value.Add(new BByteString("one"), new BByteString("value_one")); data.Value.Add(new BByteString("two"), new BInteger(1)); // Test var bot = new BObjectTransform(); bot.EncodeObject(data, outputBuffer); // Get result and check it int length = (int) outputBuffer.Position; string actualOutput = Encoding.UTF8.GetString(outputBuffer.ToArray(), 0, length); Assert.AreEqual<string>(expectedOutput, actualOutput); }
/// <summary> /// Converts the torrent to a <see cref="BDictionary"/>. /// </summary> /// <returns></returns> public virtual BDictionary ToBDictionary() { var torrent = new BDictionary(); var trackerCount = Trackers.Flatten().Count(); if (trackerCount > 0) torrent[TorrentFields.Announce] = new BList(Trackers.First().Select(x => new BString(x, Encoding))); if (trackerCount > 1) torrent[TorrentFields.AnnounceList] = new BList(Trackers.Select(x => new BList(x, Encoding))); if (Encoding != null) torrent[TorrentFields.Encoding] = new BString(Encoding.WebName.ToUpper(), Encoding); if (Comment != null) torrent[TorrentFields.Comment] = new BString(Comment, Encoding); if (CreatedBy != null) torrent[TorrentFields.CreatedBy] = new BString(CreatedBy, Encoding); if (CreationDate != null) torrent[TorrentFields.CreationDate] = (BNumber)CreationDate; var info = CreateInfoDictionary(Encoding); if (info.Any()) torrent[TorrentFields.Info] = info; if (ExtraFields != null) torrent.MergeWith(ExtraFields, ExistingKeyAction.Merge); return torrent; }
void multiFileTorrent(BDictionary info, TorrentCreationViewModel vm, List<FileInfo> files) { BList filesList = new BList(); foreach (FileInfo file in files) { BDictionary fileDictionary = new BDictionary(); fileDictionary["length"] = new BInteger(file.Length); BList pathList = new BList(); String relativePath = file.FullName.Remove(0, vm.PathRoot.Length); foreach (String elem in relativePath.Split(new char[] { '\\' })) { if (!String.IsNullOrEmpty(elem)) { pathList.Add(elem); } } fileDictionary["path"] = pathList; filesList.Add(fileDictionary); } info["name"] = new BString(vm.TorrentName); info["files"] = filesList; }
/// <summary> /// Saves a BDicionary to the provided Stream. /// </summary> /// <param name="value">The BDicionary to ba saved.</param> /// <param name="stream">The Stream to receive the saved data.</param> /// <remarks>This method is the same as the method Save, but receives a BDicionary as the value parameter because a torrent file is bencoded dictionary.</remarks> public static void SaveTorrent(BDictionary value, Stream stream) { Save(value, stream); }
public void MergeWith_NumberWithNewKeyIsAdded() { var dict1 = new BDictionary {{"key", 1}}; var dict2 = new BDictionary {{"another key", 42}}; dict1.MergeWith(dict2); dict1.Should().HaveCount(2); dict1["key"].Should().Be((BNumber) 1); dict1["another key"].Should().Be((BNumber) 42); }
public DHTMessage(MsgType type, QueryType queryType, BDictionary data) { Type = type; QueryType = queryType; Data = data; }
/// <summary> /// Creates the 'info' part of the torrent. /// </summary> /// <param name="encoding">The encoding used for writing strings</param> /// <returns>A <see cref="BDictionary"/> of the 'info' part of the torrent</returns> protected virtual BDictionary CreateInfoDictionary(Encoding encoding) { var info = new BDictionary(); if (PieceSize > 0) info[TorrentInfoFields.PieceLength] = (BNumber) PieceSize; if (Pieces?.Length > 0) info[TorrentInfoFields.Pieces] = new BString(Pieces, encoding); if (IsPrivate) info[TorrentInfoFields.Private] = (BNumber)1; if (FileMode == TorrentFileMode.Single) { info[TorrentInfoFields.Name] = new BString(File.FileName, encoding); info[TorrentInfoFields.Length] = (BNumber)File.FileSize; if (File.Md5Sum != null) info[TorrentInfoFields.Md5Sum] = new BString(File.Md5Sum, encoding); } else if (FileMode == TorrentFileMode.Multi) { info[TorrentInfoFields.Name] = new BString(Files.DirectoryName, encoding); var files = new BList<BDictionary>(); foreach (var file in Files) { var fileDictionary = new BDictionary { [TorrentFilesFields.Length] = (BNumber)file.FileSize, [TorrentFilesFields.Path] = new BList(file.Path) }; if (file.Md5Sum != null) fileDictionary[TorrentFilesFields.Md5Sum] = new BString(file.Md5Sum, encoding); files.Add(fileDictionary); } info[TorrentInfoFields.Files] = files; } return info; }
public void MergeWith_StringReplacesExistingKey() { var dict1 = new BDictionary {{"key", "value"}}; var dict2 = new BDictionary {{"key", "replaced value"}}; dict1.MergeWith(dict2); dict1.Should().HaveCount(1); dict1["key"].Should().Be((BString)"replaced value"); }
/// <summary> /// Saves a BDicionary to the provided file path. /// </summary> /// <param name="value">The BDicionary to ba saved.</param> /// <param name="path">The destination path.</param> /// <remarks>This method is the same as the method Save, but receives a BDicionary as the value parameter because a torrent file is bencoded dictionary.</remarks> public static void SaveTorrent(BDictionary value, string path) { Save(value, path); }
public void MergeWith_StringWithNewKeyIsAdded() { var dict1 = new BDictionary {{"key", "value"}}; var dict2 = new BDictionary {{"another key", "value"}}; dict1.MergeWith(dict2); dict1.Should().HaveCount(2); dict1["key"].Should().Be((BString)"value"); dict1["another key"].Should().Be((BString)"value"); }
public void SequenceEqual_WithDifferentValues_AreNotEqual() { var bdict1 = new BDictionary { {"foobar", "Hello World!"}, }; var bdict2 = new BDictionary { {"foobar", "Another world..."}, }; bdict1.SequenceEqual(bdict2).Should().BeFalse(); }
private bool Check() { if (fState == 0) { if (fDataBuffer[0] != 0x13) { throw new Exception(); } var str1 = Encoding.ASCII.GetString(fDataBuffer.ToArray(), 1, 19); if (str1 != "BitTorrent protocol") { throw new Exception(); } var reserved = fDataBuffer.Skip(20).Take(8).ToArray(); var infoHash = fDataBuffer.Skip(28).Take(20).ToArray(); if (infoHash != InfoHash) { throw new Exception(); } var peer_id = fDataBuffer.ToArray().Skip(48).Take(20); fState = 1; SendExtShakeHand(); fDataBuffer.RemoveRange(0, 68); return(true); } else if (fState == 1) { var lengthArray = fDataBuffer.Take(4); var len = BitConverter.ToUInt32(lengthArray.Reverse().ToArray(), 0); if (fDataBuffer.Count >= (4 + len)) { var dataBuf = fDataBuffer.Skip(4).Take((int)len).ToArray(); var msgid = dataBuf[0]; if (msgid != 0x08) { throw new Exception(); } var extendMsgID = dataBuf[1]; if (extendMsgID != 0x00) { throw new Exception(); } BencodeParser parse = new BencodeParser(); var supose = parse.Parse <BDictionary>(dataBuf.Skip(2).ToArray()); if (!supose.ContainsKey("m")) { throw new Exception(); } var suplist = supose.Get <BDictionary>("m"); if (!suplist.ContainsKey("ut_metadata")) { throw new Exception(); } var numid = suplist.Get <BNumber>("ut_metadata"); var size = supose.Get <BNumber>("metadata_size"); var count = size / (16 * 1024) + (size % (16 * 1024) > 0 ? 1 : 0); for (int i = 0; i < count; i++) { BDictionary data = new BDictionary(); data.Add("msg_type", 0); data.Add("prece", i); var data2 = new List <byte>(); data2.Add(0x14); data2.Add((byte)numid.Value); data2.AddRange(data.EncodeAsBytes()); data2.AddRange(BitConverter.GetBytes((UInt32)data2.Count).Reverse()); fSocket.Send(data2.ToArray()); } fState = 2; return(true); } else if (fState == 2) { } } return(false); }