예제 #1
0
        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}");
                }
            }
        }