public BlockRequestWorker(WorkerConfig workerConfig, Logger logger, LocalClient localClient, CoreDaemon coreDaemon) : base("BlockRequestWorker", workerConfig.initialNotify, workerConfig.minIdleTime, workerConfig.maxIdleTime, logger) { this.logger = logger; this.localClient = localClient; this.coreDaemon = coreDaemon; this.coreStorage = coreDaemon.CoreStorage; this.allBlockRequests = new ConcurrentDictionary <UInt256, BlockRequest>(); this.blockRequestsByPeer = new ConcurrentDictionary <Peer, ConcurrentDictionary <UInt256, DateTime> >(); this.missedBlockRequests = new ConcurrentDictionary <UInt256, BlockRequest>(); this.localClient.OnBlock += HandleBlock; this.coreDaemon.OnChainStateChanged += HandleChainStateChanged; this.coreDaemon.OnTargetChainChanged += HandleTargetChainChanged; this.coreStorage.BlockTxesMissed += HandleBlockTxesMissed; this.coreDaemon.BlockMissed += HandleBlockMissed; this.blockRequestDurationMeasure = new DurationMeasure(sampleCutoff: TimeSpan.FromMinutes(5)); this.blockDownloadRateMeasure = new RateMeasure(); this.duplicateBlockDownloadCountMeasure = new CountMeasure(TimeSpan.FromSeconds(30)); this.targetChainQueue = new List <ChainedHeader>(); this.targetChainQueueIndex = 0; this.targetChainLookAhead = 1; this.flushWorker = new WorkerMethod("BlockRequestWorker.FlushWorker", FlushWorkerMethod, initialNotify: true, minIdleTime: TimeSpan.Zero, maxIdleTime: TimeSpan.MaxValue, logger: this.logger); this.flushQueue = new ConcurrentQueue <FlushBlock>(); this.flushBlocks = new ConcurrentSet <UInt256>(); this.diagnosticWorker = new WorkerMethod("BlockRequestWorker.DiagnosticWorker", DiagnosticWorkerMethod, initialNotify: true, minIdleTime: TimeSpan.FromSeconds(10), maxIdleTime: TimeSpan.FromSeconds(10), logger: this.logger); }
public BlockRequestWorker(Logger logger, WorkerConfig workerConfig, LocalClient localClient, CoreDaemon blockchainDaemon, ChainedHeaderCache chainedHeaderCache, BlockCache blockCache) : base("BlockRequestWorker", workerConfig.initialNotify, workerConfig.minIdleTime, workerConfig.maxIdleTime, logger) { this.logger = logger; this.localClient = localClient; this.blockchainDaemon = blockchainDaemon; this.chainedHeaderCache = chainedHeaderCache; this.blockCache = blockCache; this.allBlockRequests = new ConcurrentDictionary <UInt256, DateTime>(); this.blockRequestsByPeer = new ConcurrentDictionary <IPEndPoint, ConcurrentDictionary <UInt256, DateTime> >(); this.missingBlockQueue = new SortedList <int, ChainedHeader>(); this.localClient.OnBlock += HandleBlock; this.blockchainDaemon.OnChainStateChanged += HandleChainStateChanged; this.blockchainDaemon.OnTargetChainChanged += HandleTargetChainChanged; this.blockCache.OnMissing += HandleBlockMissing; this.blockRequestDurationMeasure = new DurationMeasure(sampleCutoff: TimeSpan.FromMinutes(5)); this.blockDownloadRateMeasure = new RateMeasure(); this.duplicateBlockDownloadRateMeasure = new RateMeasure(); this.targetChainLookAhead = 1; this.criticalTargetChainLookAhead = 1; this.flushWorker = new WorkerMethod("BlockRequestWorker.FlushWorker", FlushWorkerMethod, initialNotify: true, minIdleTime: TimeSpan.Zero, maxIdleTime: TimeSpan.MaxValue, logger: this.logger); this.flushQueue = new ConcurrentQueue <Tuple <RemoteNode, Block> >(); }
public void TestRateMeasure() { // start timing var stopwatch = Stopwatch.StartNew(); var sampleCutoff = TimeSpan.FromSeconds(1); var sampleResolution = TimeSpan.FromMilliseconds(10); using (var rateMeasure = new RateMeasure(sampleCutoff, sampleResolution)) { // tick once per duration, count times var count = 10; var duration = TimeSpan.FromMilliseconds(20); for (var i = 0; i < count; i++) { Thread.Sleep(duration); rateMeasure.Tick(); } // stop timing stopwatch.Stop(); // the average rate, per the amount of the time the test has run for, should be as close as possible to count Assert.AreEqual(count, rateMeasure.GetAverage(stopwatch.Elapsed), 0.5); // wait for the cutoff time to pass and verify the rate dropped to 0 Thread.Sleep(duration + rateMeasure.SampleCutoff); Assert.AreEqual(0, rateMeasure.GetAverage(duration)); } }
public LocalClient(ChainType type, IKernel kernel, CoreDaemon coreDaemon, INetworkPeerStorage networkPeerStorage) { this.shutdownToken = new CancellationTokenSource(); this.type = type; this.kernel = kernel; this.coreDaemon = coreDaemon; this.chainParams = coreDaemon.ChainParams; this.coreStorage = coreDaemon.CoreStorage; this.networkPeerStorage = networkPeerStorage; this.messageRateMeasure = new RateMeasure(); this.headersRequestWorker = new HeadersRequestWorker( new WorkerConfig(initialNotify: true, minIdleTime: TimeSpan.FromMilliseconds(50), maxIdleTime: TimeSpan.FromSeconds(5)), this, this.coreDaemon); this.blockRequestWorker = new BlockRequestWorker( new WorkerConfig(initialNotify: true, minIdleTime: TimeSpan.FromMilliseconds(50), maxIdleTime: TimeSpan.FromSeconds(30)), this, this.coreDaemon); this.peerWorker = new PeerWorker( new WorkerConfig(initialNotify: true, minIdleTime: TimeSpan.FromSeconds(1), maxIdleTime: TimeSpan.FromSeconds(1)), this, this.coreDaemon, this.headersRequestWorker); this.listenWorker = new ListenWorker(this, this.peerWorker); this.statsWorker = new WorkerMethod("LocalClient.StatsWorker", StatsWorker, true, TimeSpan.FromSeconds(5), TimeSpan.FromMinutes(5)); this.peerWorker.PeerHandshakeCompleted += HandlePeerHandshakeCompleted; this.peerWorker.PeerDisconnected += HandlePeerDisconnected; this.blockRequestWorker.OnBlockFlushed += HandleBlockFlushed; switch (this.Type) { case ChainType.MainNet: Messaging.Port = 8333; Messaging.Magic = Messaging.MAGIC_MAIN; break; case ChainType.TestNet3: Messaging.Port = 18333; Messaging.Magic = Messaging.MAGIC_TESTNET3; break; case ChainType.Regtest: Messaging.Port = 18444; Messaging.Magic = Messaging.MAGIC_COMPARISON_TOOL; break; } }
public LocalClient(Logger logger, RulesEnum type, IKernel kernel, IBlockchainRules rules, CoreDaemon coreDaemon, NetworkPeerCache networkPeerCache) { this.shutdownToken = new CancellationTokenSource(); this.logger = logger; this.type = type; this.kernel = kernel; this.rules = rules; this.coreDaemon = coreDaemon; this.coreStorage = coreDaemon.CoreStorage; this.networkPeerCache = networkPeerCache; this.messageRateMeasure = new RateMeasure(); this.peerWorker = new PeerWorker( new WorkerConfig(initialNotify: true, minIdleTime: TimeSpan.FromSeconds(1), maxIdleTime: TimeSpan.FromSeconds(1)), this.logger, this, this.coreDaemon); this.listenWorker = new ListenWorker(this.logger, this, this.peerWorker); this.headersRequestWorker = new HeadersRequestWorker( new WorkerConfig(initialNotify: true, minIdleTime: TimeSpan.FromMilliseconds(50), maxIdleTime: TimeSpan.FromSeconds(5)), this.logger, this, this.coreDaemon); this.blockRequestWorker = new BlockRequestWorker( new WorkerConfig(initialNotify: true, minIdleTime: TimeSpan.FromMilliseconds(50), maxIdleTime: TimeSpan.FromSeconds(30)), this.logger, this, this.coreDaemon); this.statsWorker = new WorkerMethod("LocalClient.StatsWorker", StatsWorker, true, TimeSpan.FromSeconds(5), TimeSpan.FromSeconds(30), this.logger); this.peerWorker.PeerConnected += HandlePeerConnected; this.peerWorker.PeerDisconnected += HandlePeerDisconnected; switch (this.Type) { case RulesEnum.MainNet: Messaging.Port = 8333; Messaging.Magic = Messaging.MAGIC_MAIN; break; case RulesEnum.TestNet3: Messaging.Port = 18333; Messaging.Magic = Messaging.MAGIC_TESTNET3; break; case RulesEnum.ComparisonToolTestNet: Messaging.Port = 18444; Messaging.Magic = Messaging.MAGIC_COMPARISON_TOOL; break; } }
public LocalClient(Logger logger, RulesEnum type, IKernel kernel, IBlockchainRules rules, CoreDaemon blockchainDaemon, BlockHeaderCache blockHeaderCache, ChainedHeaderCache chainedHeaderCache, TransactionCache transactionCache, BlockCache blockCache, NetworkPeerCache networkPeerCache) { this.shutdownToken = new CancellationTokenSource(); this.logger = logger; this.type = type; this.kernel = kernel; this.rules = rules; this.blockchainDaemon = blockchainDaemon; this.blockHeaderCache = blockHeaderCache; this.chainedHeaderCache = chainedHeaderCache; this.transactionCache = transactionCache; this.blockCache = blockCache; this.networkPeerCache = networkPeerCache; this.messageRateMeasure = new RateMeasure(); this.connectWorker = new WorkerMethod("LocalClient.ConnectWorker", ConnectWorker, true, TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(1), this.logger); this.headersRequestWorker = kernel.Get <HeadersRequestWorker>( new ConstructorArgument("workerConfig", new WorkerConfig(initialNotify: true, minIdleTime: TimeSpan.FromMilliseconds(50), maxIdleTime: TimeSpan.FromSeconds(30))), new ConstructorArgument("localClient", this)); this.blockRequestWorker = kernel.Get <BlockRequestWorker>( new ConstructorArgument("workerConfig", new WorkerConfig(initialNotify: true, minIdleTime: TimeSpan.FromMilliseconds(50), maxIdleTime: TimeSpan.FromSeconds(30))), new ConstructorArgument("localClient", this)); this.statsWorker = new WorkerMethod("LocalClient.StatsWorker", StatsWorker, true, TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(30), this.logger); switch (this.Type) { case RulesEnum.MainNet: Messaging.Port = 8333; Messaging.Magic = Messaging.MAGIC_MAIN; break; case RulesEnum.TestNet3: Messaging.Port = 18333; Messaging.Magic = Messaging.MAGIC_TESTNET3; break; case RulesEnum.ComparisonToolTestNet: Messaging.Port = 18444; Messaging.Magic = Messaging.MAGIC_COMPARISON_TOOL; break; } }
public void TestRateMeasure() { var sampleCutoff = TimeSpan.FromSeconds(1); var sampleResolution = TimeSpan.FromMilliseconds(10); using (var rateMeasure = new RateMeasure(sampleCutoff, sampleResolution)) { // tick once per duration, count times var count = 10; var duration = TimeSpan.FromMilliseconds(20); for (var i = 0; i < count; i++) { Thread.Sleep(duration); rateMeasure.Tick(); } // the average rate per duration unit time should be as close as possible to 1 Assert.AreEqual(1, rateMeasure.GetAverage(duration), 0.1); // wait for the cutoff time to pass and verify the rate dropped to 0 Thread.Sleep(duration + rateMeasure.SampleCutoff); Assert.AreEqual(0, rateMeasure.GetAverage(duration)); } }
public BlockRequestWorker(WorkerConfig workerConfig, LocalClient localClient, CoreDaemon coreDaemon) : base("BlockRequestWorker", workerConfig.initialNotify, workerConfig.minIdleTime, workerConfig.maxIdleTime) { this.localClient = localClient; this.coreDaemon = coreDaemon; this.coreStorage = coreDaemon.CoreStorage; this.allBlockRequests = new ConcurrentDictionary <UInt256, BlockRequest>(); this.blockRequestsByPeer = new ConcurrentDictionary <Peer, ConcurrentDictionary <UInt256, DateTimeOffset> >(); this.missedBlockRequests = new ConcurrentDictionary <UInt256, BlockRequest>(); this.localClient.OnBlock += HandleBlock; this.coreDaemon.OnChainStateChanged += HandleChainStateChanged; this.coreDaemon.OnTargetChainChanged += HandleTargetChainChanged; this.coreDaemon.BlockMissed += HandleBlockMissed; this.blockRequestDurationMeasure = new DurationMeasure(sampleCutoff: TimeSpan.FromMinutes(5)); this.blockDownloadRateMeasure = new RateMeasure(); this.duplicateBlockDownloadCountMeasure = new CountMeasure(TimeSpan.FromSeconds(30)); this.targetChainQueue = new List <ChainedHeader>(); this.targetChainQueueIndex = 0; this.targetChainLookAhead = 1; this.flushWorker = new ActionBlock <FlushBlock>((Action <FlushBlock>)FlushWorkerMethod, new ExecutionDataflowBlockOptions { MaxDegreeOfParallelism = Environment.ProcessorCount }); this.flushQueue = new BufferBlock <FlushBlock>(); this.flushBlocks = new ConcurrentSet <UInt256>(); this.flushQueue.LinkTo(this.flushWorker, new DataflowLinkOptions { PropagateCompletion = true }); this.diagnosticWorker = new WorkerMethod("BlockRequestWorker.DiagnosticWorker", DiagnosticWorkerMethod, initialNotify: true, minIdleTime: TimeSpan.FromSeconds(10), maxIdleTime: TimeSpan.FromSeconds(10)); }
public static void StartDownload(Parameters parameters, Flag doneFlag, StatusDelegate statusFunction, ErrorDelegate errorFunction, FinishedDelegate finishedFunction) { if (parameters.ResponseFile.Length == 0 && parameters.Url.Length == 0) { throw new BitTorrentException("需要Response file 或者 Url"); } Parameters = parameters; Stream stream = null; byte[] response; long length = 0; try { if (parameters.ResponseFile.Length != 0) { stream = File.OpenRead(parameters.ResponseFile); length = stream.Length; } else { WebRequest webRequest = WebRequest.Create(parameters.Url); WebResponse webResponse = webRequest.GetResponse(); stream = webResponse.GetResponseStream(); length = webResponse.ContentLength; } response = new byte[length]; stream.Read(response, 0, (int)length); } catch { throw new BitTorrentException("Problem getting response info"); } finally { if (stream != null) { stream.Close(); } } DictNode rootNode; try { rootNode = BEncodingFactory.Decode(response) as DictNode; //BTFormat.CheckMessage(rootNode); } catch { throw new BitTorrentException("got bad file"); } DictNode infoNode = rootNode["info"] as DictNode; List <BitFile> files = new List <BitFile>(); string file; long fileLength; try { if (infoNode.ContainsKey("length")) { fileLength = (infoNode["length"] as IntNode).Value; BytesNode nameNode = (infoNode["name"] as BytesNode); if (nameNode == null) { return; } file = @"k:\torrent\" + nameNode.StringText; Make(file, false); files.Add(new BitFile(file, fileLength)); } else { fileLength = 0L; ListNode filesNode = infoNode["files"] as ListNode; foreach (BEncodedNode handler in filesNode) { DictNode fileNode = infoNode["files"] as DictNode; fileLength += (fileNode["length"] as IntNode).Value; } //访问文件夹 BytesNode nameNode = infoNode["name"] as BytesNode; if (nameNode == null) { return; } file = @"C:\torrent\" + nameNode.StringText; // if this path exists, and no files from the info dict exist, we assume it's a new download and // the user wants to create a new directory with the default name bool existed = false; if (Directory.Exists(file)) { foreach (BEncodedNode handler in filesNode) { DictNode fileNode = handler as DictNode; ListNode pathNode = fileNode["path"] as ListNode; if (File.Exists(Path.Combine(file, (pathNode[0] as BytesNode).StringText))) { existed = true; break; } } if (!existed) { file = Path.Combine(file, (infoNode["name"] as BytesNode).StringText); } } Make(file, true); // alert the UI to any possible change in path //TODO: if (pathFunc != null) // pathFunc(file) foreach (BEncodedNode handler in filesNode) { DictNode fileNode = handler as DictNode; ListNode pathNode = fileNode["path"] as ListNode; string n = file; foreach (BEncodedNode stringHandler in pathNode) { n = Path.Combine(n, (stringHandler as BytesNode).StringText); } files.Add(new BitFile(n, (fileNode["length"] as IntNode).Value)); Make(n, false); } } } catch { throw new BitTorrentException("Couldn't allocate directory..."); } Flag finishFlag = new Flag(); FinishedHelper finishedHelper = new FinishedHelper(); finishedHelper.ErrorFunction = errorFunction; finishedHelper.FinishedFunction = finishedFunction; finishedHelper.DoneFlag = finishFlag; string sID = DateTime.Now.ToLongDateString() + "www.wallywood.co.uk"; byte[] myID = Globals.GetSha1Hash(Encoding.ASCII.GetBytes(sID));//Globals.Sha1.ComputeHash(Encoding.Default.GetBytes(sID)); byte[] piece = (infoNode["pieces"] as BytesNode).ByteArray; List <byte[]> pieces = new List <byte[]>(); for (int i = 0; i < piece.Length; i += 20) { byte[] temp = new byte[20]; Buffer.BlockCopy(piece, i, temp, 0, 20); pieces.Add(temp); } Storage _storage = null; try { try { //_storage = new Storage(files, parameters.AllocatePause, statusFunction); finishedHelper.Storage = _storage; } catch (Exception ex) { errorFunction("trouble accessing files - " + ex.Message); } IntNode pieceLengthNode = infoNode["piece length"] as IntNode; StorageWrapper = new StorageWrapper(_storage, parameters.DownloadSliceSize, pieces, (int)pieceLengthNode.Value, finishedHelper.Finished, finishedHelper.Failed, statusFunction, finishFlag, parameters.CheckHashes, finishedHelper.DataFlunked); } // Catch ValueError // failed("bad data") // catch IO Error catch (Exception ex) { finishedHelper.Failed("Problem - " + ex.Message); } if (finishFlag.IsSet) { return; } RawServer rawServer = new RawServer(finishFlag, parameters.TimeoutCheckInterval, parameters.Timeout, false); if (parameters.MaxPort < parameters.MinPort) { int temp = parameters.MinPort; parameters.MinPort = parameters.MaxPort; parameters.MaxPort = parameters.MinPort; } ushort listenPort; for (listenPort = parameters.MinPort; listenPort <= parameters.MaxPort; listenPort++) { try { rawServer.Bind(listenPort, parameters.Bind, false); break; } catch (SocketException) { //TODO: Error Code } } //TODO: Check whether nothing bound Choker = new Choker(parameters.MaxUploads, rawServer.AddTask, finishFlag); Measure uploadMeasure = new Measure(parameters.MaxRatePeriod, parameters.UploadRateFudge); Measure downloadMeasure = new Measure(parameters.MaxRatePeriod); RateMeasure rateMeasure = new RateMeasure(StorageWrapper.LeftLength); Downloader downloader = new NormalDownloader(StorageWrapper, new PiecePicker(pieces.Count), parameters.RequestBackLog, parameters.MaxRatePeriod, pieces.Count, downloadMeasure, parameters.SnubTime, rateMeasure.DataCameIn); Connecter connecter = new Connecter(downloader, Choker, pieces.Count, StorageWrapper.IsEverythingPending, uploadMeasure, parameters.MaxUploadRate << 10, rawServer.AddTask); byte[] infoHash = Globals.GetSha1Hash(BEncodingFactory.ByteArrayEncode(infoNode));//Globals.Sha1.ComputeHash(BEncodingFactory.ByteArrayEncode(infoNode)); Encrypter encrypter = new Encrypter(connecter, rawServer, myID, parameters.MaxMessageLength, rawServer.AddTask, parameters.KeepAliveInterval, infoHash, parameters.MaxInitiate); //ReRequester reRequester = // new ReRequester((rootNode["announce"] as BytesNode).StringText, parameters.RerequestInterval, // rawServer.AddTask, connecter.GetConnectionsCount, parameters.MinPeers, // encrypter.StartConnect, rawServer.AddExternalTask, // StorageWrapper.GetLeftLength, uploadMeasure.GetTotalLength, downloadMeasure.GetTotalLength, // listenPort, parameters.IP, // myID, infoHash, parameters.HttpTimeout, null, parameters.MaxInitiate, finishFlag); DownloaderFeedback downloaderFeedback = new DownloaderFeedback(Choker, rawServer.AddTask, statusFunction, uploadMeasure.GetUpdatedRate, downloadMeasure.GetUpdatedRate, rateMeasure.GetTimeLeft, rateMeasure.GetLeftTime, fileLength, finishFlag, parameters.DisplayInterval, parameters.Spew); statusFunction("connection to peers", -1, -1, -1, -1); //TODO: finishedHelper.errorfunc finishedHelper.FinishFlag = finishFlag; //finishedHelper.ReRequester = reRequester; finishedHelper.RateMeasure = rateMeasure; //reRequester.d(0); rawServer.ListenForever(encrypter); //reRequester.Announce(2, null); }