public static bool broadcastGetBlock(ulong block_num, RemoteEndpoint skipEndpoint = null, RemoteEndpoint endpoint = null, byte include_transactions = 0, bool full_header = false) { using (MemoryStream mw = new MemoryStream()) { using (BinaryWriter writerw = new BinaryWriter(mw)) { writerw.WriteIxiVarInt(block_num); writerw.Write(include_transactions); writerw.Write(full_header); #if TRACE_MEMSTREAM_SIZES Logging.info(String.Format("NetworkProtocol::broadcastGetBlock: {0}", mw.Length)); #endif if (endpoint != null) { if (endpoint.isConnected()) { endpoint.sendData(ProtocolMessageCode.getBlock3, mw.ToArray()); return(true); } } return(CoreProtocolMessage.broadcastProtocolMessageToSingleRandomNode(new char[] { 'M', 'H' }, ProtocolMessageCode.getBlock3, mw.ToArray(), block_num, skipEndpoint)); } } }
public static bool broadcastGetBlockSignatures(ulong block_num, byte[] block_checksum, RemoteEndpoint endpoint) { using (MemoryStream mw = new MemoryStream()) { using (BinaryWriter writerw = new BinaryWriter(mw)) { writerw.WriteIxiVarInt(block_num); writerw.WriteIxiVarInt(block_checksum.Length); writerw.Write(block_checksum); #if TRACE_MEMSTREAM_SIZES Logging.info(String.Format("NetworkProtocol::broadcastGetBlockSignatures: {0}", mw.Length)); #endif if (endpoint != null) { if (endpoint.isConnected()) { endpoint.sendData(ProtocolMessageCode.getBlockSignatures2, mw.ToArray()); return(true); } } return(CoreProtocolMessage.broadcastProtocolMessageToSingleRandomNode(new char[] { 'M', 'H' }, ProtocolMessageCode.getBlockSignatures2, mw.ToArray(), block_num)); } } }
public static bool broadcastNewBlock(Block b, RemoteEndpoint skipEndpoint = null, RemoteEndpoint endpoint = null, bool force_broadcast = false) { if (!Node.isMasterNode()) { return(true); } if (endpoint != null) { if (endpoint.isConnected()) { endpoint.sendData(ProtocolMessageCode.blockData, b.getBytes(false), BitConverter.GetBytes(b.blockNum)); return(true); } return(false); } else { if (force_broadcast) { return(CoreProtocolMessage.broadcastProtocolMessage(new char[] { 'M', 'H' }, ProtocolMessageCode.blockData, b.getBytes(false), BitConverter.GetBytes(b.blockNum), skipEndpoint)); } else { return(CoreProtocolMessage.addToInventory(new char[] { 'M', 'H' }, new InventoryItemBlock(b.blockChecksum, b.blockNum), skipEndpoint, ProtocolMessageCode.blockData, b.getBytes(false), BitConverter.GetBytes(b.blockNum))); } } }
public override bool addTransaction(Transaction tx, bool force_broadcast) { // TODO Send to peer if directly connectable CoreProtocolMessage.broadcastProtocolMessage(new char[] { 'M', 'H' }, ProtocolMessageCode.transactionData, tx.getBytes(), null); PendingTransactions.addPendingLocalTransaction(tx); return(true); }
private static void acceptConnection(Socket clientSocket) { IPEndPoint clientEndpoint = (IPEndPoint)clientSocket.RemoteEndPoint; // Add timeouts and set socket options //clientSocket.ReceiveTimeout = 5000; //clientSocket.SendTimeout = 5000; clientSocket.LingerState = new LingerOption(true, 3); clientSocket.NoDelay = true; clientSocket.Blocking = true; if (!IxianHandler.isAcceptingConnections()) { Thread.Sleep(100); // wait a bit for check connectivity purposes clientSocket.Send(CoreProtocolMessage.prepareProtocolMessage(ProtocolMessageCode.bye, new byte[1])); clientSocket.Shutdown(SocketShutdown.Both); clientSocket.Disconnect(true); return; } lastIncomingConnectionTime = DateTime.UtcNow; connectable = true; // Setup the remote endpoint RemoteEndpoint remoteEndpoint = new RemoteEndpoint(); lock (connectedClients) { if (connectedClients.Count + 1 > CoreConfig.maximumServerMasterNodes) { Logging.warn(string.Format("Maximum number of connected clients reached. Disconnecting client: {0}:{1}", clientEndpoint.Address.ToString(), clientEndpoint.Port)); clientSocket.Send(CoreProtocolMessage.prepareProtocolMessage(ProtocolMessageCode.bye, new byte[1])); clientSocket.Shutdown(SocketShutdown.Both); clientSocket.Disconnect(true); return; } var existing_clients = connectedClients.Where(re => re.remoteIP.Address == clientEndpoint.Address); if (existing_clients.Count() > 0) { Logging.warn(String.Format("Client {0}:{1} already connected as {2}.", clientEndpoint.Address.ToString(), clientEndpoint.Port, existing_clients.First().ToString())); clientSocket.Send(CoreProtocolMessage.prepareProtocolMessage(ProtocolMessageCode.bye, new byte[1])); clientSocket.Shutdown(SocketShutdown.Both); clientSocket.Disconnect(true); return; } connectedClients.Add(remoteEndpoint); Logging.info(String.Format("Client connection accepted: {0} | #{1}/{2}", clientEndpoint.ToString(), connectedClients.Count + 1, CoreConfig.maximumServerMasterNodes)); remoteEndpoint.start(clientSocket); } }
static void handleHello(byte[] data, RemoteEndpoint endpoint) { using (MemoryStream m = new MemoryStream(data)) { using (BinaryReader reader = new BinaryReader(m)) { CoreProtocolMessage.processHelloMessageV6(endpoint, reader); } } }
private static void acceptConnection(Socket clientSocket) { IPEndPoint clientEndpoint = (IPEndPoint)clientSocket.RemoteEndPoint; // Add timeouts and set socket options //clientSocket.ReceiveTimeout = 5000; //clientSocket.SendTimeout = 5000; clientSocket.LingerState = new LingerOption(true, 3); clientSocket.NoDelay = true; clientSocket.Blocking = true; if (!IxianHandler.isAcceptingConnections()) { CoreProtocolMessage.sendBye(clientSocket, ProtocolByeCode.notReady, string.Format("The node isn't ready yet, please try again later."), ""); clientSocket.Shutdown(SocketShutdown.Both); clientSocket.Disconnect(true); return; } lastIncomingConnectionTime = DateTime.UtcNow; connectable = true; // Setup the remote endpoint RemoteEndpoint remoteEndpoint = new RemoteEndpoint(); lock (connectedClients) { if (connectedClients.Count + 1 > CoreConfig.maximumServerMasterNodes) { Logging.warn("Maximum number of connected clients reached. Disconnecting client: {0}:{1}", clientEndpoint.Address.ToString(), clientEndpoint.Port); CoreProtocolMessage.sendBye(clientSocket, ProtocolByeCode.rejected, "Too many clients already connected.", ""); clientSocket.Shutdown(SocketShutdown.Both); clientSocket.Disconnect(true); return; } var existing_clients = connectedClients.Where(re => re.remoteIP.Address == clientEndpoint.Address); if (existing_clients.Count() > 0) { Logging.warn("Client {0}:{1} already connected as {2}.", clientEndpoint.Address.ToString(), clientEndpoint.Port, existing_clients.First().ToString()); CoreProtocolMessage.sendBye(clientSocket, ProtocolByeCode.rejected, "You are already connected.", ""); clientSocket.Shutdown(SocketShutdown.Both); clientSocket.Disconnect(true); return; } connectedClients.Add(remoteEndpoint); Logging.info("Client connection accepted: {0} | #{1}/{2}", clientEndpoint.ToString(), connectedClients.Count + 1, CoreConfig.maximumServerMasterNodes); remoteEndpoint.start(clientSocket); } }
public static void processPendingTransactions() { // TODO TODO improve to include failed transactions ulong last_block_height = IxianHandler.getLastBlockHeight(); lock (PendingTransactions.pendingTransactions) { long cur_time = Clock.getTimestamp(); List <PendingTransaction> tmp_pending_transactions = new List <PendingTransaction>(PendingTransactions.pendingTransactions); int idx = 0; foreach (var entry in tmp_pending_transactions) { Transaction t = entry.transaction; long tx_time = entry.addedTimestamp; if (t.applied != 0) { PendingTransactions.pendingTransactions.RemoveAll(x => x.transaction.id.SequenceEqual(t.id)); continue; } // if transaction expired, remove it from pending transactions if (last_block_height > ConsensusConfig.getRedactedWindowSize() && t.blockHeight < last_block_height - ConsensusConfig.getRedactedWindowSize()) { ActivityStorage.updateStatus(t.id, ActivityStatus.Error, 0); PendingTransactions.pendingTransactions.RemoveAll(x => x.transaction.id.SequenceEqual(t.id)); continue; } if (cur_time - tx_time > 40) // if the transaction is pending for over 40 seconds, resend { CoreProtocolMessage.broadcastProtocolMessage(new char[] { 'M', 'H' }, ProtocolMessageCode.transactionData, t.getBytes(), null); entry.addedTimestamp = cur_time; entry.confirmedNodeList.Clear(); } if (entry.confirmedNodeList.Count() >= 3) // if we get transaction from 3 nodes, we can consider it as confirmed { if (entry.messageId != null) { StreamProcessor.confirmMessage(entry.messageId); } continue; } if (cur_time - tx_time > 20) // if the transaction is pending for over 20 seconds, send inquiry { CoreProtocolMessage.broadcastGetTransaction(t.id, 0, null, false); } idx++; } } }
/// <summary> /// Attempts to connect to the given host name or IP address and transmit some data. /// Note: This function has a possible delay of about 2 seconds. /// </summary> /// <param name="full_hostname">Hostname or IP address of the remote endpoint.</param> /// <returns>True, if the IP address is reachable.</returns> public static bool PingAddressReachable(String full_hostname) { // TODO TODO TODO TODO move this to another thread if (String.IsNullOrWhiteSpace(full_hostname)) { return(false); } String[] hn_port = full_hostname.Split(':'); if (hn_port.Length != 2) { return(false); } String hostname = hn_port[0]; if (!IXICore.Utils.IxiUtils.validateIPv4(hostname)) { return(false); } int port; if (int.TryParse(hn_port[1], out port) == false) { return(false); } if (port <= 0) { return(false); } TcpClient temp = new TcpClient(); bool connected = false; try { Logging.info("Testing client connectivity for {0}.", full_hostname); if (!temp.ConnectAsync(hostname, port).Wait(1000)) { return(false); } temp.Client.SendTimeout = 500; temp.Client.ReceiveTimeout = 500; temp.Client.Blocking = false; temp.Client.Send(new byte[1], 1, 0); connected = temp.Client.Connected; CoreProtocolMessage.sendBye(temp.Client, ProtocolByeCode.bye, "Test OK", ""); temp.Client.Shutdown(SocketShutdown.Both); temp.Close(); temp.Dispose(); } catch (Exception) { connected = false; } return(connected); }
private static void subscribeToEvents(RemoteEndpoint endpoint) { CoreProtocolMessage.subscribeToEvents(endpoint); byte[] friend_matcher = FriendList.getFriendCuckooFilter(); if (friend_matcher != null) { byte[] event_data = NetworkEvents.prepareEventMessageData(NetworkEvents.Type.keepAlive, friend_matcher); endpoint.sendData(ProtocolMessageCode.attachEvent, event_data); } }
private bool handleSignature(InventoryItem item, RemoteEndpoint endpoint) { InventoryItemSignature iis = (InventoryItemSignature)item; ulong last_block_height = IxianHandler.getLastBlockHeight(); byte[] address = iis.address; ulong block_num = iis.blockNum; if (block_num + 5 > last_block_height && block_num <= last_block_height + 1) { if (block_num == last_block_height + 1) { lock (Node.blockProcessor.localBlockLock) { Block local_block = Node.blockProcessor.localNewBlock; if (local_block == null || local_block.blockNum != block_num) { return(false); } if (!local_block.blockChecksum.SequenceEqual(iis.blockHash) || local_block.hasNodeSignature(address)) { return(false); } } } else { Block sf_block = Node.blockChain.getBlock(block_num); if (!sf_block.blockChecksum.SequenceEqual(iis.blockHash) || sf_block.hasNodeSignature(address)) { return(false); } } byte[] block_num_bytes = block_num.GetIxiVarIntBytes(); byte[] addr_len_bytes = ((ulong)address.Length).GetIxiVarIntBytes(); byte[] data = new byte[block_num_bytes.Length + 1 + addr_len_bytes.Length + address.Length]; Array.Copy(block_num_bytes, data, block_num_bytes.Length); data[block_num_bytes.Length] = 1; Array.Copy(addr_len_bytes, 0, data, block_num_bytes.Length + 1, addr_len_bytes.Length); Array.Copy(address, 0, data, block_num_bytes.Length + 1 + addr_len_bytes.Length, address.Length); if (endpoint == null) { CoreProtocolMessage.broadcastProtocolMessageToSingleRandomNode(new char[] { 'M', 'H' }, ProtocolMessageCode.getSignatures, data, block_num); } else { endpoint.sendData(ProtocolMessageCode.getSignatures, data, null); } return(true); } return(false); }
private void stopSyncStartBlockProcessing() { if (CoreConfig.preventNetworkOperations) { Logging.info("Data verification successfully completed."); IxianHandler.forceShutdown = true; syncDone = true; synchronizing = false; return; } // Don't finish sync if we never synchronized from network if (noNetworkSynchronization == true) { Thread.Sleep(500); return; } IxianHandler.status = NodeStatus.ready; // if we reach here, we are synchronized syncDone = true; synchronizing = false; Node.blockProcessor.firstBlockAfterSync = true; Node.blockProcessor.resumeOperation(); lock (pendingBlocks) { lock (requestedBlockTimes) { requestedBlockTimes.Clear(); } pendingBlocks.Clear(); if (missingBlocks != null) { missingBlocks.Clear(); missingBlocks = null; } } if (!Config.recoverFromFile) { CoreProtocolMessage.broadcastProtocolMessageToSingleRandomNode(new char[] { 'M' }, ProtocolMessageCode.getUnappliedTransactions, new byte[1], IxianHandler.getHighestKnownNetworkBlockHeight()); Node.miner.start(); Node.walletStorage.scanForLostAddresses(); } }
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); } }
public static FriendMessage addMessageWithType(byte[] id, FriendMessageType type, byte[] wallet_address, string message, bool local_sender = false) { foreach (Friend friend in friends) { if (friend.walletAddress.SequenceEqual(wallet_address)) { Node.shouldRefreshContacts = true; if (!friend.online) { using (MemoryStream mw = new MemoryStream()) { using (BinaryWriter writer = new BinaryWriter(mw)) { writer.Write(wallet_address.Length); writer.Write(wallet_address); CoreProtocolMessage.broadcastProtocolMessage(new char[] { 'M' }, ProtocolMessageCode.getPresence, mw.ToArray(), null); } } } // TODO: message date should be fetched, not generated here FriendMessage friend_message = new FriendMessage(id, message, Clock.getTimestamp(), local_sender, type); friend.messages.Add(friend_message); // If a chat page is visible, insert the message directly if (friend.chat_page != null) { friend.chat_page.insertMessage(friend_message); } else { //CrossLocalNotifications.Current.Show(string.Format("New message from {0}",friend.nickname), message, 100, DateTime.Now.AddSeconds(1)); } // Write to chat history Node.localStorage.writeMessagesFile(wallet_address, friend.messages); return(friend_message); } } // No matching contact found in friendlist // Add the contact, then issue the message again // TODO: need to fetch the stage 1 public key somehow here // Ignoring such messages for now //addFriend(wallet_address, "pubkey", "Unknown"); //addMessage(wallet_address, message); return(null); }
// Request transaction data private void requestTransactionData() { Logging.info("Requesting transaction data for: {0}", transaction.id); using (MemoryStream m = new MemoryStream()) { using (BinaryWriter writer = new BinaryWriter(m)) { writer.Write(transaction.id); writer.Write((ulong)0); CoreProtocolMessage.broadcastProtocolMessageToSingleRandomNode(new char[] { 'M' }, IXICore.Network.ProtocolMessageCode.getTransaction, m.ToArray(), 0, null); } } }
public static void processPendingTransactions() { // TODO TODO improve to include failed transactions ulong last_block_height = IxianHandler.getLastBlockHeight(); lock (PendingTransactions.pendingTransactions) { long cur_time = Clock.getTimestamp(); List <PendingTransaction> tmp_pending_transactions = new List <PendingTransaction>(PendingTransactions.pendingTransactions); int idx = 0; foreach (var entry in tmp_pending_transactions) { Transaction t = entry.transaction; long tx_time = entry.addedTimestamp; if (t.applied != 0) { PendingTransactions.pendingTransactions.RemoveAll(x => x.transaction.id.SequenceEqual(t.id)); continue; } // if transaction expired, remove it from pending transactions if (last_block_height > ConsensusConfig.getRedactedWindowSize() && t.blockHeight < last_block_height - ConsensusConfig.getRedactedWindowSize()) { Console.WriteLine("Error sending the transaction {0}", Transaction.txIdV8ToLegacy(t.id)); PendingTransactions.pendingTransactions.RemoveAll(x => x.transaction.id.SequenceEqual(t.id)); continue; } if (cur_time - tx_time > 40) // if the transaction is pending for over 40 seconds, resend { CoreProtocolMessage.broadcastProtocolMessage(new char[] { 'M', 'H' }, ProtocolMessageCode.transactionData, t.getBytes(), null); entry.addedTimestamp = cur_time; entry.confirmedNodeList.Clear(); } if (entry.confirmedNodeList.Count() > 3) // already received 3+ feedback { continue; } if (cur_time - tx_time > 20) // if the transaction is pending for over 20 seconds, send inquiry { CoreProtocolMessage.broadcastGetTransaction(Transaction.txIdV8ToLegacy(t.id), 0); } idx++; } } }
// Handle timer routines static public void mainLoop() { byte[] primaryAddress = IxianHandler.getWalletStorage().getPrimaryAddress(); if (primaryAddress == null) { return; } byte[] getBalanceBytes; using (MemoryStream mw = new MemoryStream()) { using (BinaryWriter writer = new BinaryWriter(mw)) { writer.WriteIxiVarInt(primaryAddress.Length); writer.Write(primaryAddress); } getBalanceBytes = mw.ToArray(); } while (running) { try { // Update the friendlist FriendList.Update(); // Request initial wallet balance if (balance.blockHeight == 0 || balance.lastUpdate + 300 < Clock.getTimestamp()) { CoreProtocolMessage.broadcastProtocolMessage(new char[] { 'M', 'H' }, ProtocolMessageCode.getBalance2, getBalanceBytes, null); } if (Config.enablePushNotifications) { OfflinePushMessages.fetchPushMessages(); } // Cleanup the presence list // TODO: optimize this by using a different thread perhaps PresenceList.performCleanup(); } catch (Exception e) { Logging.error("Exception occured in mainLoop: " + e); } Thread.Sleep(2500); } }
// 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(); }
// Retrieve a presence entry connected S2 node. Returns null if not found public static string getRelayHostname(byte[] wallet_address) { string hostname = null; Presence presence = PresenceList.getPresenceByAddress(wallet_address); if (presence == null) { using (MemoryStream mw = new MemoryStream()) { using (BinaryWriter writer = new BinaryWriter(mw)) { writer.Write(wallet_address.Length); writer.Write(wallet_address); CoreProtocolMessage.broadcastProtocolMessage(new char[] { 'M' }, ProtocolMessageCode.getPresence, mw.ToArray(), null); } } return(null); } byte[] wallet = presence.wallet; lock (presence) { // Go through each presence address searching for C nodes foreach (PresenceAddress addr in presence.addresses) { // Only check Client nodes if (addr.type == 'C') { // We have a potential candidate here, store it hostname = addr.address; string[] hostname_split = hostname.Split(':'); if (hostname_split.Count() == 2 && NetworkUtils.validateIP(hostname_split[0])) { break; } } } } // Finally, return the ip address of the node return(hostname); }
// Checks for missing clients private static void reconnectClients(Random rnd) { try { handleDisconnectedClients(); if (CoreConfig.simultaneousConnectedNeighbors < 4) { Logging.error("Setting CoreConfig.simultanousConnectedNeighbors should be at least 4."); IxianHandler.shutdown(); throw new Exception("Setting CoreConfig.simultanousConnectedNeighbors should be at least 4."); } // Check if we need to connect to more neighbors if (getConnectedClients().Count() < CoreConfig.simultaneousConnectedNeighbors) { // Scan for and connect to a new neighbor connectToRandomNeighbor(); return; } else if (getConnectedClients(true).Count() > CoreConfig.simultaneousConnectedNeighbors) { NetworkClient client; lock (networkClients) { client = networkClients[0]; networkClients.RemoveAt(0); } CoreProtocolMessage.sendBye(client, ProtocolByeCode.bye, "Disconnected for shuffling purposes.", "", false); client.stop(); } // Connect randomly to a new node. Currently a 1% chance to reconnect during this iteration if (rnd.Next(100) == 1) { connectToRandomNeighbor(); } } catch (ThreadAbortException) { } catch (Exception e) { Logging.error("Fatal exception occured in NetworkClientManager.reconnectClients: " + e); } }
public static void handleHelloData(byte[] data, RemoteEndpoint endpoint) { using (MemoryStream m = new MemoryStream(data)) { using (BinaryReader reader = new BinaryReader(m)) { if (!CoreProtocolMessage.processHelloMessageV6(endpoint, reader)) { return; } 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.ReadIxiVarUInt(); int bcLen = (int)reader.ReadIxiVarUInt(); byte[] block_checksum = reader.ReadBytes(bcLen); endpoint.blockHeight = last_block_num; if (Node.checkCurrentBlockDeprecation(last_block_num) == false) { CoreProtocolMessage.sendBye(endpoint, ProtocolByeCode.deprecated, string.Format("This node deprecated or will deprecate on block {0}, your block height is {1}, disconnecting.", Config.nodeDeprecationBlock, last_block_num), last_block_num.ToString(), true); return; } int block_version = (int)reader.ReadIxiVarUInt(); ulong highest_block_height = IxianHandler.getHighestKnownNetworkBlockHeight(); if (last_block_num + 15 < highest_block_height) { CoreProtocolMessage.sendBye(endpoint, ProtocolByeCode.tooFarBehind, string.Format("Your node is too far behind, your block height is {0}, highest network block height is {1}.", last_block_num, highest_block_height), highest_block_height.ToString(), true); return; } // Process the hello data Node.blockSync.onHelloDataReceived(last_block_num, block_checksum, block_version, null, 0, 0, true); endpoint.helloReceived = true; NetworkClientManager.recalculateLocalTimeDifference(); } } }
// Receive thread protected override void recvLoop() { try { Random rnd = new Random(); CoreProtocolMessage.sendHelloMessageV6(this, false, rnd.Next()); base.recvLoop(); }catch (Exception e) { if (running) { Logging.warn(string.Format("recvRE: Disconnected client {0} with exception {1}", getFullAddress(), e.ToString())); } state = RemoteEndpointState.Closed; running = false; } }
// Sends data over the network public static void sendData(ProtocolMessageCode code, byte[] data) { byte[] ba = CoreProtocolMessage.prepareProtocolMessage(code, data); NetDump.Instance.appendSent(tcpClient.Client, ba, ba.Length); try { tcpClient.Client.Send(ba, SocketFlags.None); if (tcpClient.Client.Connected == false) { Logging.error("Failed senddata to client. Reconnecting."); } } catch (Exception e) { Logging.error(String.Format("CLN: Socket exception, attempting to reconnect {0}", e)); } //Console.WriteLine("sendData done"); }
// Internal function that sends data through the socket protected void sendDataInternal(ProtocolMessageCode code, byte[] data, byte[] checksum) { byte[] ba = CoreProtocolMessage.prepareProtocolMessage(code, data, checksum); NetDump.Instance.appendSent(clientSocket, ba, ba.Length); try { for (int sentBytes = 0; sentBytes < ba.Length && running;) { int bytesToSendCount = ba.Length - sentBytes; if (bytesToSendCount > 8000) { bytesToSendCount = 8000; } int curSentBytes = clientSocket.Send(ba, sentBytes, bytesToSendCount, SocketFlags.None); lastDataSentTime = Clock.getTimestamp(); // Sleep a bit to allow other threads to do their thing Thread.Yield(); sentBytes += curSentBytes; // TODO TODO TODO timeout } if (clientSocket.Connected == false) { if (running) { Logging.warn(String.Format("sendRE: Failed senddata to remote endpoint {0}, Closing.", getFullAddress())); } state = RemoteEndpointState.Closed; } } catch (Exception e) { if (running) { Logging.warn(String.Format("sendRE: Socket exception for {0}, closing. {1}", getFullAddress(), e)); } state = RemoteEndpointState.Closed; } }
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); } } } } }
// Broadcast the current block height. Called after accepting a new block once the node is fully synced // Returns false when no RemoteEndpoints found to send the message to public static bool broadcastBlockHeight(ulong blockNum, byte[] checksum) { using (MemoryStream mw = new MemoryStream()) { using (BinaryWriter writerw = new BinaryWriter(mw)) { Block tmp_block = IxianHandler.getLastBlock(); // Send the block height writerw.Write(blockNum); // Send the block checksum for this balance writerw.Write(checksum.Length); writerw.Write(checksum); return(CoreProtocolMessage.broadcastProtocolMessage(new char[] { 'C' }, ProtocolMessageCode.blockHeight, mw.ToArray(), null, null)); } } }
// Checks for missing clients private static void reconnectClients() { Random rnd = new Random(); // Wait 5 seconds before starting the loop Thread.Sleep(CoreConfig.networkClientReconnectInterval); while (autoReconnect) { TLC.Report(); handleDisconnectedClients(); // Check if we need to connect to more neighbors if (getConnectedClients().Count() < CoreConfig.simultaneousConnectedNeighbors) { // Scan for and connect to a new neighbor connectToRandomNeighbor(); } else if (getConnectedClients().Count() > CoreConfig.simultaneousConnectedNeighbors) { List <NetworkClient> netClients = null; lock (networkClients) { netClients = new List <NetworkClient>(networkClients); } CoreProtocolMessage.sendBye(netClients[0], ProtocolByeCode.bye, "Disconnected for shuffling purposes.", "", false); lock (networkClients) { networkClients.Remove(netClients[0]); } } // Connect randomly to a new node. Currently a 1% chance to reconnect during this iteration if (rnd.Next(100) == 1) { connectToRandomNeighbor(); } // Wait 5 seconds before rechecking Thread.Sleep(CoreConfig.networkClientReconnectInterval); } }
private int getDataLengthFromMessageHeader(List <byte> header) { int data_length = -1; // we should have the full header, save the data length using (MemoryStream m = new MemoryStream(header.ToArray())) { using (BinaryReader reader = new BinaryReader(m)) { reader.ReadByte(); // skip start byte int code = reader.ReadInt32(); // skip message code data_length = reader.ReadInt32(); // finally read data length byte[] data_checksum = reader.ReadBytes(32); // skip checksum sha512qu/sha512sq, 32 bytes byte checksum = reader.ReadByte(); // header checksum byte byte endByte = reader.ReadByte(); // end byte if (endByte != 'I') { Logging.warn("Header end byte was not 'I'"); return(-1); } if (CoreProtocolMessage.getHeaderChecksum(header.Take(41).ToArray()) != checksum) { Logging.warn(String.Format("Header checksum mismatch")); return(-1); } if (data_length <= 0) { Logging.warn(String.Format("Data length was {0}, code {1}", data_length, code)); return(-1); } if (data_length > CoreConfig.maxMessageSize) { Logging.warn(String.Format("Received data length was bigger than max allowed message size - {0}, code {1}.", data_length, code)); return(-1); } } } return(data_length); }
// Parse thread protected void parseLoop() { // Prepare an special message object to use while sending, without locking up the queue messages QueueMessageRaw active_message = new QueueMessageRaw(); while (running) { TLC.Report(); try { bool message_found = false; lock (recvRawQueueMessages) { if (recvRawQueueMessages.Count > 0) { // Pick the oldest message QueueMessageRaw candidate = recvRawQueueMessages[0]; active_message.data = candidate.data; active_message.endpoint = candidate.endpoint; // Remove it from the queue recvRawQueueMessages.Remove(candidate); message_found = true; } } if (message_found) { // Active message set, add it to Network Queue CoreProtocolMessage.readProtocolMessage(active_message.data, this); } else { Thread.Sleep(10); } } catch (Exception e) { Logging.error(String.Format("Exception occured for client {0} in parseLoopRE: {1} ", getFullAddress(), e)); } // Sleep a bit to prevent cpu waste Thread.Yield(); } }
// Called when receiving a transaction signature from a client public static void receivedTransactionSignature(byte[] bytes, RemoteEndpoint endpoint) { using (MemoryStream m = new MemoryStream(bytes)) { using (BinaryReader reader = new BinaryReader(m)) { // Read the message ID string messageID = reader.ReadString(); int sig_length = reader.ReadInt32(); if (sig_length <= 0) { Logging.warn("Incorrect signature length received."); return; } // Read the signature byte[] signature = reader.ReadBytes(sig_length); lock (transactions) { // Find the transaction with a matching message id StreamTransaction tx = transactions.Find(x => x.messageID.Equals(messageID, StringComparison.Ordinal)); if (tx == null) { Logging.warn("No transaction found to match signature messageID."); return; } // Compose a new transaction and apply the received signature Transaction transaction = new Transaction(tx.transaction); transaction.signature = signature; // Verify the signed transaction if (transaction.verifySignature(transaction.pubKey, null)) { // Broadcast the transaction CoreProtocolMessage.broadcastProtocolMessage(new char[] { 'M', 'H' }, ProtocolMessageCode.transactionData, transaction.getBytes(), null, endpoint); } return; } } } }