// Starts the Network Client Manager. First it connects to one of the seed nodes in order to fetch the Presence List.
        // Afterwards, it starts the reconnect and keepalive threads
        public static void start()
        {
            if (running)
            {
                return;
            }
            running        = true;
            networkClients = new List <NetworkClient>();

            PeerStorage.readPeersFile();

            // Now add the seed nodes to the list
            foreach (string[] addr in CoreNetworkUtils.getSeedNodes(Config.isTestNet))
            {
                byte[] wallet_addr = null;
                if (addr[1] != null)
                {
                    wallet_addr = Base58Check.Base58CheckEncoding.DecodePlain(addr[1]);
                }
                PeerStorage.addPeerToPeerList(addr[0], wallet_addr, false);
            }

            // Connect to a random node first
            bool firstSeedConnected = false;

            while (firstSeedConnected == false)
            {
                Peer p = PeerStorage.getRandomMasterNodeAddress();
                if (p != null)
                {
                    firstSeedConnected = connectTo(p.hostname, p.walletAddress);
                }
                if (firstSeedConnected == false)
                {
                    Thread.Sleep(1000);
                }
            }

            // Start the reconnect thread
            TLC                  = new ThreadLiveCheck();
            reconnectThread      = new Thread(reconnectClients);
            reconnectThread.Name = "Network_Client_Manager_Reconnect";
            autoReconnect        = true;
            reconnectThread.Start();
        }
예제 #2
0
        // Starts the Network Client Manager. First it connects to one of the seed nodes in order to fetch the Presence List.
        // Afterwards, it starts the reconnect and keepalive threads
        public static void start()
        {
            if (running)
            {
                return;
            }
            running        = true;
            networkClients = new List <NetworkClient>();

            PeerStorage.readPeersFile();

            // Now add the seed nodes to the list
            foreach (string addr in CoreNetworkUtils.getSeedNodes(Config.isTestNet))
            {
                PeerStorage.addPeerToPeerList(addr, null, false);
            }

            // Connect to a random node first
            bool firstSeedConnected = false;

            while (firstSeedConnected == false)
            {
                string address = PeerStorage.getRandomMasterNodeAddress();
                if (address != "")
                {
                    firstSeedConnected = connectTo(address);
                }
                if (firstSeedConnected == false)
                {
                    Thread.Sleep(1000);
                }
            }

            // Start the reconnect thread
            TLC                  = new ThreadLiveCheck();
            reconnectThread      = new Thread(reconnectClients);
            reconnectThread.Name = "Network_Client_Manager_Reconnect";
            autoReconnect        = true;
            reconnectThread.Start();
        }
        // Returns a random new potential neighbor. Returns null if no new neighbor is found.
        public static Peer scanForNeighbor()
        {
            Peer connectToPeer = null;

            // Find only masternodes
            while (connectToPeer == null)
            {
                bool addr_valid = true;
                Peer p          = PeerStorage.getRandomMasterNodeAddress();

                if (p == null)
                {
                    break;
                }

                // Next, check if we're connecting to a self address of this node
                string[] server = p.hostname.Split(':');

                if (server.Length < 2)
                {
                    break;
                }

                // Resolve the hostname first
                string resolved_server_name           = NetworkUtils.resolveHostname(server[0]);
                string resolved_server_name_with_port = resolved_server_name + ":" + server[1];

                // Check if we are already connected to this address
                lock (networkClients)
                {
                    foreach (NetworkClient client in networkClients)
                    {
                        if (client.getFullAddress(true).Equals(resolved_server_name_with_port, StringComparison.Ordinal))
                        {
                            // Address is already in the client list
                            addr_valid = false;
                            break;
                        }
                    }
                }

                // Check if node is already in the server list
                string[] connectedClients = NetworkServer.getConnectedClients(true);
                for (int i = 0; i < connectedClients.Length; i++)
                {
                    if (connectedClients[i].Equals(resolved_server_name_with_port, StringComparison.Ordinal))
                    {
                        // Address is already in the client list
                        addr_valid = false;
                        break;
                    }
                }

                if (addr_valid == false)
                {
                    continue;
                }

                // Check against connecting clients list as well
                lock (connectingClients)
                {
                    foreach (string client in connectingClients)
                    {
                        if (resolved_server_name_with_port.Equals(client, StringComparison.Ordinal))
                        {
                            // Address is already in the connecting client list
                            addr_valid = false;
                            break;
                        }
                    }
                }

                if (addr_valid == false)
                {
                    continue;
                }

                // Get all self addresses and run through them
                List <string> self_addresses = CoreNetworkUtils.GetAllLocalIPAddresses();
                foreach (string self_address in self_addresses)
                {
                    // Don't connect to self
                    if (resolved_server_name.Equals(self_address, StringComparison.Ordinal))
                    {
                        if (server[1].Equals(string.Format("{0}", Config.serverPort), StringComparison.Ordinal))
                        {
                            addr_valid = false;
                        }
                    }
                }

                // If the address is valid, add it to the candidates
                if (addr_valid)
                {
                    connectToPeer = p;
                }
            }

            return(connectToPeer);
        }
예제 #4
0
        // Called when receiving a keepalive network message. The PresenceList will update the appropriate entry based on the timestamp.
        // Returns TRUE if it updated an entry in the PL
        // Sets the out address parameter to be the KA wallet's address or null if an error occured
        public static bool receiveKeepAlive(byte[] bytes, out byte[] address)
        {
            address = null;

            // Get the current timestamp
            long currentTime = Core.getCurrentTimestamp();

            try
            {
                using (MemoryStream m = new MemoryStream(bytes))
                {
                    using (BinaryReader reader = new BinaryReader(m))
                    {
                        int    keepAliveVersion = reader.ReadInt32();
                        int    walletLen        = reader.ReadInt32();
                        byte[] wallet           = reader.ReadBytes(walletLen);

                        // Assign the out address parameter
                        address = wallet;

                        string deviceid  = reader.ReadString();
                        long   timestamp = reader.ReadInt64();
                        string hostname  = reader.ReadString();
                        char   node_type = '0';
                        if (keepAliveVersion > 0)
                        {
                            node_type = reader.ReadChar();
                        }
                        int    sigLen    = reader.ReadInt32();
                        byte[] signature = reader.ReadBytes(sigLen);
                        //Logging.info(String.Format("[PL] KEEPALIVE request from {0}", hostname));

                        if (node_type == 'C' || node_type == 'R')
                        {
                            // all good, continue
                        }
                        else if (node_type == 'M' || node_type == 'H')
                        {
                            // check balance
                            if (Node.walletState.getWalletBalance(wallet) < CoreConfig.minimumMasterNodeFunds)
                            {
                                return(false);
                            }
                        }
                        else if (node_type != '0')
                        {
                            // reject everything else
                            return(false);
                        }

                        lock (presences)
                        {
                            Presence listEntry = presences.Find(x => x.wallet.SequenceEqual(wallet));
                            if (listEntry == null && wallet.SequenceEqual(Node.walletStorage.getPrimaryAddress()))
                            {
                                Logging.error(string.Format("My entry was removed from local PL, readding."));
                                updateEntry(curNodePresence);
                                listEntry = presences.Find(x => x.wallet.SequenceEqual(wallet));
                            }

                            // Check if no such wallet found in presence list
                            if (listEntry == null)
                            {
                                // request for additional data
                                using (MemoryStream mw = new MemoryStream())
                                {
                                    using (BinaryWriter writer = new BinaryWriter(mw))
                                    {
                                        writer.Write(wallet.Length);
                                        writer.Write(wallet);

                                        CoreProtocolMessage.broadcastProtocolMessage(new char[] { 'M', 'R' }, ProtocolMessageCode.getPresence, mw.ToArray(), null);
                                    }
                                }
                                return(false);
                            }
                            if (keepAliveVersion == 0)
                            {
                                // Verify the signature
                                if (CryptoManager.lib.verifySignature(Encoding.UTF8.GetBytes(CoreConfig.ixianChecksumLockString + "-" + deviceid + "-" + timestamp + "-" + hostname), listEntry.pubkey, signature) == false)
                                {
                                    Logging.warn(string.Format("[PL] KEEPALIVE tampering for {0} {1}, incorrect Sig.", Base58Check.Base58CheckEncoding.EncodePlain(listEntry.wallet), hostname));
                                    return(false);
                                }
                            }
                            else
                            {
                                // Verify the signature
                                if (CryptoManager.lib.verifySignature(bytes.Take(bytes.Length - sigLen - 4).ToArray(), listEntry.pubkey, signature) == false)
                                {
                                    Logging.warn(string.Format("[PL] KEEPALIVE tampering for {0} {1}, incorrect Sig.", Base58Check.Base58CheckEncoding.EncodePlain(listEntry.wallet), hostname));
                                    return(false);
                                }
                            }

                            PresenceAddress pa = listEntry.addresses.Find(x => x.address == hostname && x.device == deviceid);

                            if (pa != null)
                            {
                                // Check the node type
                                if (pa.lastSeenTime != timestamp)
                                {
                                    // Check for outdated timestamp
                                    if (timestamp < pa.lastSeenTime)
                                    {
                                        // We already have a newer timestamp for this entry
                                        return(false);
                                    }

                                    // Check for tampering. Includes a +300, -30 second synchronization zone
                                    if ((currentTime - timestamp) > 300 || (currentTime - timestamp) < -30)
                                    {
                                        Logging.warn(string.Format("[PL] Potential KEEPALIVE tampering for {0} {1}. Timestamp {2}", Base58Check.Base58CheckEncoding.EncodePlain(listEntry.wallet), pa.address, timestamp));
                                        return(false);
                                    }

                                    // Update the timestamp
                                    pa.lastSeenTime = timestamp;
                                    pa.signature    = signature;
                                    if (node_type != '0')
                                    {
                                        if (pa.type != node_type)
                                        {
                                            lock (presenceCount)
                                            {
                                                presenceCount[pa.type]--;
                                                if (!presenceCount.ContainsKey(node_type))
                                                {
                                                    presenceCount.Add(node_type, 0);
                                                }
                                                presenceCount[node_type]++;
                                            }
                                        }
                                        pa.type = node_type;
                                    }

                                    if (pa.type == 'M' || pa.type == 'H')
                                    {
                                        PeerStorage.addPeerToPeerList(hostname, wallet);
                                    }

                                    //Console.WriteLine("[PL] LASTSEEN for {0} - {1} set to {2}", hostname, deviceid, pa.lastSeenTime);
                                    return(true);
                                }
                            }
                            else
                            {
                                if (wallet.SequenceEqual(Node.walletStorage.getPrimaryAddress()))
                                {
                                    updateEntry(curNodePresence);
                                    return(true);
                                }
                                else
                                {
                                    using (MemoryStream mw = new MemoryStream())
                                    {
                                        using (BinaryWriter writer = new BinaryWriter(mw))
                                        {
                                            writer.Write(wallet.Length);
                                            writer.Write(wallet);

                                            CoreProtocolMessage.broadcastProtocolMessage(new char[] { 'M', 'R' }, ProtocolMessageCode.getPresence, mw.ToArray(), null);
                                        }
                                    }
                                    return(false);
                                }
                            }
                        }
                    }
                }
            }
            catch (Exception e)
            {
                Logging.error("Exception occured in receiveKeepAlive: " + e);
                return(false);
            }

            return(false);
        }