private void GetPeers(Node node, int selfRecursionLevel = 0) { try { /* BEndode get_peers Response * * "t" -> <transId>, * "y" -> "r", * "r" -> { "id" -> <nodeId> , "token" -> <token> , "nodes" -> "nodeId + host + port...", "values" -> [host + port, ...] } * */ if (options.Verbosity > 0) { Log($"[{node.distance}] [{node.host}] [REQ ]"); } requested++; BDictionary bResponse = GetResponse(node); if (bResponse == null || !bResponse.ContainsKey("y") || ((BString)bResponse["y"]).ToString() != "r") { node.status = Node.Status.FAILED; if (!options.Beggar.Stats.BoostMode) { lock (rememberBadNodes) rememberBadNodes.Add(node.host); } if (bResponse != null) { bResponse.Clear(); } if (options.Verbosity > 0) { Log($"[{node.distance}] [{node.host}] [RESP] Failed"); } return; } if (options.Verbosity > 0) { Log($"[{node.distance}] [{node.host}] [RESP]"); } bResponse = (BDictionary)bResponse["r"]; // r -> Nodes if (bResponse.ContainsKey("nodes")) { byte[] curNodes = ((BString)bResponse["nodes"]).Value.ToArray(); for (int i = 0; i < curNodes.Length; i += 26) { byte[] curNodeId = Utils.ArraySub(ref curNodes, (uint)i, 20, false); short curDistance = isWeirdStrategy ? CalculateDistance(curNodeId) : CalculateDistance2(curNodeId); string curIP = (new IPAddress(Utils.ArraySub(ref curNodes, (uint)i + 20, 4))).ToString(); UInt16 curPort = (UInt16)BitConverter.ToInt16(Utils.ArraySub(ref curNodes, (uint)i + 24, 2, true), 0); if (curPort < 100) { continue; // Drop fake } if (i > (5 * 26) && curDistance > minBucketDistance) { break; // Avoid collecting too many nodes out of distance from a single node } if (options.Verbosity > 0) { Log($"[{node.distance}] [{node.host}] [NODE] [{curDistance}] {curIP}:{curPort}"); } lock (lockerNodes) { if (!bucketNodesPointer.ContainsKey(curIP) && !rememberBadNodes.Contains(curIP)) { AddNewNode(curIP, curPort, curDistance); } } } } // r -> Peers if (bResponse.ContainsKey("values")) { int newPeers = 0; BList values = (BList)bResponse["values"]; if (values.Count == 0) { node.status = Node.Status.REQUESTED; responded++; bResponse.Clear(); return; } Dictionary <string, int> curPeers = new Dictionary <string, int>(); if (isWeirdStrategy) { weirdPeers += values.Count; } else { normalPeers += values.Count; } //node.hasPeers = true; havePeers++; foreach (IBObject cur in values) { byte[] value = ((BString)cur).Value.ToArray(); string curIP = (new IPAddress(Utils.ArraySub(ref value, 0, 4))).ToString(); UInt16 curPort = (UInt16)BitConverter.ToInt16(Utils.ArraySub(ref value, 4, 2, true), 0); if (curPort < 500) { continue; // Drop fake / Avoid DDOS } //if (options.Verbosity > 0) Log($"[{node.distance}] [{node.host}] [PEER] {curIP}:{curPort}"); curPeers[curIP] = curPort; } if (curPeers.Count > 0) { options.Beggar.FillPeers(curPeers, BitSwarm.PeersStorage.DHT); } //if (options.Verbosity > 0) Log($"[{node.distance}] [{node.host}] [NEW PEERS] {newPeers}"); // Re-requesting same Node with Peers > 99 (max returned peers are 100?) // Possible fake/random peers (escape recursion? 30 loops?) | NOTE: we loosing sync with scheduler because of that if (status == Status.RUNNING && values.Count > 99) { if (selfRecursionLevel > 30) { if (options.Verbosity > 0) { Log($"[{node.distance}] [{node.host}] [RE-REQUEST LIMIT EXCEEDED]"); } } else { selfRecursionLevel++; if (options.Verbosity > 0) { Log($"[{node.distance}] [{node.host}] [RE-REQUEST {selfRecursionLevel}] {newPeers}"); } Thread.Sleep(10); GetPeers(node, selfRecursionLevel); } } } node.status = Node.Status.REQUESTED; responded++; bResponse.Clear(); } catch (Exception e) { node.status = Node.Status.FAILED; if (options.Verbosity > 0) { Log($"[{node.distance}] [{node.host}] [ERROR] {e.Message}\r\n{e.StackTrace}"); } } }