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