public async Task <IEnumerable <Node> > ExecuteAsync() { var activeQueries = new List <Task <SendQueryEventArgs> > (); var closestNodes = new ClosestNodesCollection(InfoHash); var closestActiveNodes = new ClosestNodesCollection(InfoHash); foreach (Node node in Engine.RoutingTable.GetClosest(InfoHash)) { if (closestNodes.Add(node)) { activeQueries.Add(Engine.SendQueryAsync(new GetPeers(Engine.LocalId, InfoHash), node)); } } while (activeQueries.Count > 0) { var completed = await Task.WhenAny(activeQueries); activeQueries.Remove(completed); // If it timed out or failed just move to the next query. SendQueryEventArgs query = await completed; if (query.Response == null) { continue; } var response = (GetPeersResponse)query.Response; // The response had some actual peers if (response.Values != null) { // We have actual peers! var peers = Peer.Decode(response.Values); Engine.RaisePeersFound(InfoHash, peers); foreach (var peer in peers) { FoundPeers.Add(peer); } } // The response contains nodes which should be closer to our target. If they are closer than nodes // we've already checked, then let's query them! if (response.Nodes != null && FoundPeers.Count < MaxPeers) { foreach (Node node in Node.FromCompactNode(response.Nodes)) { if (closestNodes.Add(node)) { activeQueries.Add(Engine.SendQueryAsync(new GetPeers(Engine.LocalId, InfoHash), node)); } } } closestActiveNodes.Add(query.Node); } // Finally, return the 8 closest nodes we discovered during this phase. These are the nodes we should // announce to later. return(closestActiveNodes); }
void TaskComplete(object sender, TaskCompleteEventArgs e) { e.Task.Completed -= TaskComplete; // I should raise the event with some eventargs saying which node was dead SendQueryEventArgs args = (SendQueryEventArgs)e; if (args.TimedOut) { // If the node didn't respond and it's no longer in our bucket, // we need to send a ping to the oldest node in the bucket // Otherwise if we have a non-responder and it's still there, replace it! int index = bucket.Nodes.IndexOf(((SendQueryTask)e.Task).Target); if (index < 0) { SendPingToOldest(); } else { bucket.Nodes[index] = newNode; RaiseComplete(new TaskCompleteEventArgs(this)); } } else { SendPingToOldest(); } }
private static void FindNodeComplete(object sender, TaskCompleteEventArgs e) { SendQueryEventArgs args = (SendQueryEventArgs)e; lock (engine) activities--; if (!args.TimedOut) { logAdd("Visited"); if (find_queue.Count < 10000) { FindNodeResponse response = (FindNodeResponse)args.Response; var ns = Node.FromCompactNode(response.Nodes); foreach (var n in ns) { //Console.WriteLine("Find {1} Node: {0}", n.Id, nodes.Count); lock (find_queue) find_queue.Enqueue(n); } } } else { nodes.RemoveWhere(n => ((FindNode)args.Query).Target == n.Id); } }
private void MessageSent(object sender, SendQueryEventArgs e) { if (e.Query != query) { return; } // If the message timed out and we we haven't already hit the maximum retries // send again. Otherwise we propagate the eventargs through the Complete event. if (e.TimedOut) { node.FailedCount++; } else { Target.LastSeen = DateTime.UtcNow; } if (e.TimedOut && --retries > 0) { engine.MessageLoop.EnqueueSend(query, node); } else { RaiseComplete(e); } }
private void GetPeersCompleted(object o, TaskCompleteEventArgs e) { try { activeQueries--; e.Task.Completed -= GetPeersCompleted; SendQueryEventArgs args = (SendQueryEventArgs)e; // We want to keep a list of the top (K) closest nodes which have responded Node target = ((SendQueryTask)args.Task).Target; int index = queriedNodes.Values.IndexOf(target); if (index >= Bucket.MaxCapacity || args.TimedOut) { queriedNodes.RemoveAt(index); } if (args.TimedOut) { return; } GetPeersResponse response = (GetPeersResponse)args.Response; // Ensure that the local Node object has the token. There may/may not be // an additional copy in the routing table depending on whether or not // it was able to fit into the table. target.Token = response.Token; if (response.Values != null) { // We have actual peers! engine.RaisePeersFound(infoHash, MonoTorrent.Client.Peer.Decode(response.Values)); } else if (response.Nodes != null) { if (!Active) { return; } // We got a list of nodes which are closer IEnumerable <Node> newNodes = Node.FromCompactNode(response.Nodes); foreach (Node n in Node.CloserNodes(infoHash, closestNodes, newNodes, Bucket.MaxCapacity)) { SendGetPeers(n); } } } finally { if (activeQueries == 0) { RaiseComplete(new TaskCompleteEventArgs(this)); } } }
private void FindNodeComplete(object sender, TaskCompleteEventArgs e) { e.Task.Completed -= FindNodeComplete; activeRequests--; SendQueryEventArgs args = (SendQueryEventArgs)e; if (!args.TimedOut) { FindNodeResponse response = (FindNodeResponse)args.Response; SendFindNode(Node.FromCompactNode(response.Nodes)); } if (activeRequests == 0) { RaiseComplete(new TaskCompleteEventArgs(this)); } }
async Task SendFindNode(IEnumerable <Node> newNodes) { var activeRequests = new List <Task <SendQueryEventArgs> > (); var nodes = new ClosestNodesCollection(engine.LocalId); foreach (Node node in newNodes) { var request = new FindNode(engine.LocalId, engine.LocalId); activeRequests.Add(engine.SendQueryAsync(request, node)); nodes.Add(node); } while (activeRequests.Count > 0) { var completed = await Task.WhenAny(activeRequests); activeRequests.Remove(completed); SendQueryEventArgs args = await completed; if (args.Response != null) { if (engine.RoutingTable.CountNodes() >= MinHealthyNodes) { initializationComplete.TrySetResult(null); } var response = (FindNodeResponse)args.Response; foreach (Node node in Node.FromCompactNode(response.Nodes)) { if (nodes.Add(node)) { var request = new FindNode(engine.LocalId, engine.LocalId); activeRequests.Add(engine.SendQueryAsync(request, node)); } } } } if (initialNodes.Count > 0 && engine.RoutingTable.NeedsBootstrap) { await new InitialiseTask(engine).ExecuteAsync(); } }
public async System.Threading.Tasks.Task Execute() { if (bucket.Nodes.Count == 0) { return; } bucket.Changed(); bucket.SortBySeen(); if (bucket.Nodes[0].LastSeen < TimeSpan.FromMinutes(3)) { return; } else { Node oldest = bucket.Nodes[0]; SendQueryEventArgs args = await engine.SendQueryAsync(new Ping (engine.LocalId), oldest); if (args.TimedOut) { // If the node didn't respond and it's no longer in our bucket, // we need to send a ping to the oldest node in the bucket // Otherwise if we have a non-responder and it's still there, replace it! int index = bucket.Nodes.IndexOf(oldest); if (index < 0) { await Execute(); } else { bucket.Nodes[index] = newNode; return; } } else { await Execute(); } } }
private void MessageSent(object sender, SendQueryEventArgs e) { if (e.Query != query) return; // If the message timed out and we we haven't already hit the maximum retries // send again. Otherwise we propagate the eventargs through the Complete event. if (e.TimedOut) node.FailedCount++; else Target.LastSeen = DateTime.UtcNow; if (e.TimedOut && --retries > 0) { engine.MessageLoop.EnqueueSend(query, node); } else { RaiseComplete(e); } }
public async Task Execute() { if (bucket.Nodes.Count == 0) { return; } bucket.SortBySeen(); foreach (Node node in bucket.Nodes.ToArray()) { var message = new FindNode(engine.LocalId, node.Id); SendQueryEventArgs args = await engine.SendQueryAsync(message, node); if (!args.TimedOut) { return; } } }
private void TaskComplete(object o, TaskCompleteEventArgs e) { _task.Completed -= TaskComplete; SendQueryEventArgs args = (SendQueryEventArgs)e; if (args.TimedOut) { _bucket.SortBySeen(); int index = _bucket.Nodes.IndexOf(_node); if ((index == -1) || (++index < _bucket.Nodes.Count)) { QueryNode(_bucket.Nodes[0]); } else { RaiseComplete(new TaskCompleteEventArgs(this)); } } else { RaiseComplete(new TaskCompleteEventArgs(this)); } }