// 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(); }
// 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); }
// 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); }