public static void handleUpdatePresence(byte[] data, RemoteEndpoint endpoint) { // Parse the data and update entries in the presence list Presence updated_presence = PresenceList.updateFromBytes(data); // If a presence entry was updated, broadcast this message again if (updated_presence != null) { CoreProtocolMessage.broadcastProtocolMessage(new char[] { 'M', 'H', 'W' }, ProtocolMessageCode.updatePresence, data, updated_presence.wallet, endpoint); // Send this keepalive message to all subscribed clients CoreProtocolMessage.broadcastEventDataMessage(NetworkEvents.Type.keepAlive, updated_presence.wallet, ProtocolMessageCode.updatePresence, data, updated_presence.wallet, endpoint); } }
// Sends perioding keepalive network messages private static void keepAlive() { while (autoKeepalive) { TLC.Report(); // Wait x seconds before rechecking for (int i = 0; i < CoreConfig.keepAliveInterval; i++) { if (autoKeepalive == false) { Thread.Yield(); return; } // Sleep for one second Thread.Sleep(1000); } if (curNodePresenceAddress.type == 'W') { continue; // no need to send PL for worker nodes } try { byte[] ka_bytes = null; ka_bytes = keepAlive_v1(); byte[] address = null; // Update self presence PresenceList.receiveKeepAlive(ka_bytes, out address); // Send this keepalive to all connected non-clients CoreProtocolMessage.broadcastProtocolMessage(new char[] { 'M', 'R', 'H', 'W' }, ProtocolMessageCode.keepAlivePresence, ka_bytes, address); // Send this keepalive message to all connected clients CoreProtocolMessage.broadcastEventDataMessage(NetworkEvents.Type.keepAlive, address, ProtocolMessageCode.keepAlivePresence, ka_bytes, address); } catch (Exception) { continue; } } Thread.Yield(); }
public static void handleKeepAlivesChunk(byte[] data, RemoteEndpoint endpoint) { using (MemoryStream m = new MemoryStream(data)) { using (BinaryReader reader = new BinaryReader(m)) { int ka_count = (int)reader.ReadIxiVarUInt(); int max_ka_per_chunk = CoreConfig.maximumKeepAlivesPerChunk; if (ka_count > max_ka_per_chunk) { ka_count = max_ka_per_chunk; } for (int i = 0; i < ka_count; i++) { if (m.Position == m.Length) { break; } int ka_len = (int)reader.ReadIxiVarUInt(); byte[] ka_bytes = reader.ReadBytes(ka_len); byte[] hash = Crypto.sha512sqTrunc(ka_bytes); Node.inventoryCache.setProcessedFlag(InventoryItemTypes.keepAlive, hash, true); byte[] address; long last_seen; byte[] device_id; bool updated = PresenceList.receiveKeepAlive(ka_bytes, out address, out last_seen, out device_id, endpoint); // If a presence entry was updated, broadcast this message again if (updated) { CoreProtocolMessage.addToInventory(new char[] { 'M', 'H', 'W' }, new InventoryItemKeepAlive(hash, last_seen, address, device_id), endpoint, ProtocolMessageCode.keepAlivePresence, ka_bytes, address); // Send this keepalive message to all subscribed clients CoreProtocolMessage.broadcastEventDataMessage(NetworkEvents.Type.keepAlive, address, ProtocolMessageCode.keepAlivePresence, ka_bytes, address, endpoint); } } } } }
public static void handleKeepAlivePresence(byte[] data, RemoteEndpoint endpoint) { byte[] address = null; long last_seen = 0; byte[] device_id = null; byte[] hash = Crypto.sha512sqTrunc(data); Node.inventoryCache.setProcessedFlag(InventoryItemTypes.keepAlive, hash, true); bool updated = PresenceList.receiveKeepAlive(data, out address, out last_seen, out device_id, endpoint); // If a presence entry was updated, broadcast this message again if (updated) { CoreProtocolMessage.addToInventory(new char[] { 'M', 'H', 'W' }, new InventoryItemKeepAlive(hash, last_seen, address, device_id), endpoint, ProtocolMessageCode.keepAlivePresence, data, address); // Send this keepalive message to all subscribed clients CoreProtocolMessage.broadcastEventDataMessage(NetworkEvents.Type.keepAlive, address, ProtocolMessageCode.keepAlivePresence, data, address, endpoint); } }
// Unified protocol message parsing public static void parseProtocolMessage(ProtocolMessageCode code, byte[] data, RemoteEndpoint endpoint) { if (endpoint == null) { Logging.error("Endpoint was null. parseProtocolMessage"); return; } try { switch (code) { case ProtocolMessageCode.hello: using (MemoryStream m = new MemoryStream(data)) { using (BinaryReader reader = new BinaryReader(m)) { if (CoreProtocolMessage.processHelloMessage(endpoint, reader)) { int challenge_len = reader.ReadInt32(); byte[] challenge = reader.ReadBytes(challenge_len); byte[] challenge_response = CryptoManager.lib.getSignature(challenge, Node.walletStorage.getPrimaryPrivateKey()); CoreProtocolMessage.sendHelloMessage(endpoint, true, challenge_response); endpoint.helloReceived = true; return; } } } break; case ProtocolMessageCode.helloData: using (MemoryStream m = new MemoryStream(data)) { using (BinaryReader reader = new BinaryReader(m)) { if (CoreProtocolMessage.processHelloMessage(endpoint, reader)) { char node_type = endpoint.presenceAddress.type; if (node_type != 'M' && node_type != 'H') { CoreProtocolMessage.sendBye(endpoint, ProtocolByeCode.expectingMaster, string.Format("Expecting master node."), "", true); return; } ulong last_block_num = reader.ReadUInt64(); int bcLen = reader.ReadInt32(); byte[] block_checksum = reader.ReadBytes(bcLen); int wsLen = reader.ReadInt32(); byte[] walletstate_checksum = reader.ReadBytes(wsLen); int consensus = reader.ReadInt32(); endpoint.blockHeight = last_block_num; int block_version = reader.ReadInt32(); Node.setLastBlock(last_block_num, block_checksum, walletstate_checksum, block_version); // Check for legacy level ulong legacy_level = reader.ReadUInt64(); // deprecated int challenge_response_len = reader.ReadInt32(); byte[] challenge_response = reader.ReadBytes(challenge_response_len); if (!CryptoManager.lib.verifySignature(endpoint.challenge, endpoint.serverPubKey, challenge_response)) { CoreProtocolMessage.sendBye(endpoint, ProtocolByeCode.authFailed, string.Format("Invalid challenge response."), "", true); return; } // Process the hello data endpoint.helloReceived = true; NetworkClientManager.recalculateLocalTimeDifference(); } } } break; case ProtocolMessageCode.s2data: { StreamProcessor.receiveData(data, endpoint); } break; case ProtocolMessageCode.s2failed: { using (MemoryStream m = new MemoryStream(data)) { using (BinaryReader reader = new BinaryReader(m)) { Logging.error("Failed to send s2 data"); } } } break; case ProtocolMessageCode.s2signature: { StreamProcessor.receivedTransactionSignature(data, endpoint); } break; case ProtocolMessageCode.newTransaction: { // Forward the new transaction message to the DLT network CoreProtocolMessage.broadcastProtocolMessage(new char[] { 'M', 'H' }, ProtocolMessageCode.newTransaction, data, null); } break; case ProtocolMessageCode.presenceList: { Logging.info("Receiving complete presence list"); PresenceList.syncFromBytes(data); } break; case ProtocolMessageCode.updatePresence: { // Parse the data and update entries in the presence list PresenceList.updateFromBytes(data); } break; case ProtocolMessageCode.keepAlivePresence: { byte[] address = null; bool updated = PresenceList.receiveKeepAlive(data, out address, endpoint); // If a presence entry was updated, broadcast this message again if (updated) { CoreProtocolMessage.broadcastProtocolMessage(new char[] { 'M', 'R', 'H', 'W' }, ProtocolMessageCode.keepAlivePresence, data, address, endpoint); // Send this keepalive message to all connected clients CoreProtocolMessage.broadcastEventDataMessage(NetworkEvents.Type.keepAlive, address, ProtocolMessageCode.keepAlivePresence, data, address, endpoint); } } break; case ProtocolMessageCode.getPresence: { using (MemoryStream m = new MemoryStream(data)) { using (BinaryReader reader = new BinaryReader(m)) { int walletLen = reader.ReadInt32(); byte[] wallet = reader.ReadBytes(walletLen); Presence p = PresenceList.getPresenceByAddress(wallet); if (p != null) { lock (p) { byte[][] presence_chunks = p.getByteChunks(); foreach (byte[] presence_chunk in presence_chunks) { endpoint.sendData(ProtocolMessageCode.updatePresence, presence_chunk, null); } } } else { // TODO blacklisting point Logging.warn(string.Format("Node has requested presence information about {0} that is not in our PL.", Base58Check.Base58CheckEncoding.EncodePlain(wallet))); } } } } break; case ProtocolMessageCode.balance: { // TODO: make sure this is received from a DLT node only. using (MemoryStream m = new MemoryStream(data)) { using (BinaryReader reader = new BinaryReader(m)) { int address_length = reader.ReadInt32(); byte[] address = reader.ReadBytes(address_length); // Retrieve the latest balance IxiNumber balance = reader.ReadString(); if (address.SequenceEqual(Node.walletStorage.getPrimaryAddress())) { Node.balance = balance; } // Retrieve the blockheight for the balance ulong blockheight = reader.ReadUInt64(); Node.blockHeight = blockheight; } } } break; case ProtocolMessageCode.bye: { using (MemoryStream m = new MemoryStream(data)) { using (BinaryReader reader = new BinaryReader(m)) { endpoint.stop(); bool byeV1 = false; try { ProtocolByeCode byeCode = (ProtocolByeCode)reader.ReadInt32(); string byeMessage = reader.ReadString(); string byeData = reader.ReadString(); byeV1 = true; switch (byeCode) { case ProtocolByeCode.bye: // all good break; case ProtocolByeCode.forked: // forked node disconnected Logging.info(string.Format("Disconnected with message: {0} {1}", byeMessage, byeData)); break; case ProtocolByeCode.deprecated: // deprecated node disconnected Logging.info(string.Format("Disconnected with message: {0} {1}", byeMessage, byeData)); break; case ProtocolByeCode.incorrectIp: // incorrect IP if (IxiUtils.validateIPv4(byeData)) { if (NetworkClientManager.getConnectedClients(true).Length < 2) { IxianHandler.publicIP = byeData; Logging.info("Changed internal IP Address to " + byeData + ", reconnecting"); } } break; case ProtocolByeCode.notConnectable: // not connectable from the internet Logging.error("This node must be connectable from the internet, to connect to the network."); Logging.error("Please setup uPNP and/or port forwarding on your router for port " + IxianHandler.publicPort + "."); NetworkServer.connectable = false; break; case ProtocolByeCode.insufficientFunds: break; default: Logging.warn(string.Format("Disconnected with message: {0} {1}", byeMessage, byeData)); break; } } catch (Exception) { } if (byeV1) { return; } reader.BaseStream.Seek(0, SeekOrigin.Begin); // Retrieve the message string message = reader.ReadString(); if (message.Length > 0) { Logging.info(string.Format("Disconnected with message: {0}", message)); } else { Logging.info("Disconnected"); } } } } break; case ProtocolMessageCode.extend: { if (Config.isTestClient) { TestClientNode.handleExtendProtocol(data); } } break; default: break; } } catch (Exception e) { Logging.error(string.Format("Error parsing network message. Details: {0}", e.ToString())); } }