Ejemplo n.º 1
0
        /// <summary>
        ///  Sends the specified network message to the given address, if it is known and connected among clients.
        /// </summary>
        /// <param name="address">Ixian Wallet Address - the recipient of the message</param>
        /// <param name="code">Type of the network message to send</param>
        /// <param name="message">Byte-field with the required data, as specified by `code`.</param>
        /// <returns>True, if the message was delivered.</returns>
        public static bool forwardMessage(byte[] address, ProtocolMessageCode code, byte[] message)
        {
            if (address == null)
            {
                Logging.warn("Cannot forward message to null address.");
                return(false);
            }

            Logging.info(String.Format(">>>> Preparing to forward to {0}",
                                       Base58Check.Base58CheckEncoding.EncodePlain(address)));

            lock (connectedClients)
            {
                foreach (RemoteEndpoint endpoint in connectedClients)
                {
                    // Skip connections without presence information
                    if (endpoint.presence == null)
                    {
                        continue;
                    }

                    byte[] client_wallet = endpoint.presence.wallet;

                    if (client_wallet != null && address.SequenceEqual(client_wallet))
                    {
                        Logging.info(">>>> Forwarding message");
                        endpoint.sendData(code, message);
                    }
                }
            }

            // TODO: broadcast to network if no connect clients found?

            return(false);
        }
Ejemplo n.º 2
0
        /// <summary>
        ///  Sends the specified network message to all connected clients
        /// </summary>
        /// <param name="address">Ixian Wallet Address - the recipient of the message</param>
        /// <param name="code">Type of the network message to send</param>
        /// <param name="message">Byte-field with the required data, as specified by `code`.</param>
        /// <returns>True, if the message was delivered.</returns>
        public static bool forwardMessage(ProtocolMessageCode code, byte[] message, byte[] exclude_address = null)
        {
            Logging.info(String.Format(">>>> Preparing to forward to everyone"));

            QueueMessage queue_message = RemoteEndpoint.getQueueMessage(code, message, null);

            lock (connectedClients)
            {
                foreach (RemoteEndpoint endpoint in connectedClients)
                {
                    // Skip connections without presence information
                    if (endpoint.presence == null)
                    {
                        continue;
                    }

                    byte[] client_wallet = endpoint.presence.wallet;

                    if (client_wallet != null)
                    {
                        if (exclude_address != null && client_wallet.SequenceEqual(exclude_address))
                        {
                            continue;
                        }
                        Logging.info(">>>> Forwarding message");
                        endpoint.sendData(queue_message);
                    }
                }
            }

            return(false);
        }
Ejemplo n.º 3
0
        // Send data to all connected nodes
        // Returns true if the data was sent to at least one client
        public static bool broadcastData(ProtocolMessageCode code, byte[] data, RemoteEndpoint skipEndpoint = null)
        {
            bool result = false;

            lock (streamClients)
            {
                foreach (NetworkClient client in streamClients)
                {
                    if (client.isConnected())
                    {
                        if (skipEndpoint != null)
                        {
                            if (client == skipEndpoint)
                            {
                                continue;
                            }
                        }

                        if (client.helloReceived == false)
                        {
                            continue;
                        }

                        client.sendData(code, data);
                        result = true;
                    }
                }
            }
            return(result);
        }
Ejemplo n.º 4
0
 public static void parseProtocolMessage(ProtocolMessageCode code, byte[] data, RemoteEndpoint endpoint)
 {
     if (handlerClass == null)
     {
         throw new Exception("Handler Class must be specified in IxianHandler Class");
     }
     handlerClass.parseProtocolMessage(code, data, endpoint);
 }
Ejemplo n.º 5
0
 private static byte[] extractHelperData(ProtocolMessageCode code, byte[] data)
 {
     if (code == ProtocolMessageCode.blockData || code == ProtocolMessageCode.newBlock)
     {
         return(data.Take(8).ToArray());
     }
     return(null);
 }
Ejemplo n.º 6
0
        /// <summary>
        ///  Reads a protocol message from the specified byte-field and calls appropriate methods to process this message.
        /// </summary>
        /// <remarks>
        ///  This function checks all applicable checksums and validates that the message is complete before calling one of the specialized
        ///  methods to handle actual decoding and processing.
        /// </remarks>
        /// <param name="recv_buffer">Byte-field with an Ixian protocol message.</param>
        /// <param name="endpoint">Remote endpoint from where the message was received.</param>
        public static void readProtocolMessage(QueueMessageRaw raw_message, MessagePriority priority, RemoteEndpoint endpoint)
        {
            if (endpoint == null)
            {
                Logging.error("Endpoint was null. readProtocolMessage");
                return;
            }

            ProtocolMessageCode code = raw_message.code;

            // Filter messages
            if (endpoint.presence == null)
            {
                // Check for presence and only accept hello and bye messages if there is no presence.
                if (code != ProtocolMessageCode.hello &&
                    code != ProtocolMessageCode.helloData &&
                    code != ProtocolMessageCode.bye)
                {
                    return;
                }
            }
            if (raw_message.legacyChecksum != null)
            {
                // Compute checksum of received data
                byte[] local_checksum = Crypto.sha512sqTrunc(raw_message.data, 0, 0, 32);

                // Verify the checksum before proceeding
                if (local_checksum.SequenceEqual(raw_message.legacyChecksum) == false)
                {
                    Logging.error("Dropped message (invalid legacy checksum)");
                    return;
                }
            }
            else
            {
                // Compute checksum of received data
                uint local_checksum = Crc32CAlgorithm.Compute(raw_message.data);

                // Verify the checksum before proceeding
                if (local_checksum != raw_message.checksum)
                {
                    Logging.error("Dropped message (invalid checksum)");
                    return;
                }
            }


            // Can proceed to parse the data parameter based on the protocol message code.
            // Data can contain multiple elements.
            //parseProtocolMessage(code, data, socket, endpoint);
            NetworkQueue.receiveProtocolMessage(code, raw_message.data, Crc32CAlgorithm.Compute(raw_message.data), priority, endpoint);
        }
Ejemplo n.º 7
0
        /// <summary>
        ///  Sends the specified event to all connected clients.
        ///  The information is only sent to those clients who have previously subscribed to this event type
        /// </summary>
        /// <param name="type">Types of the event that has occurred.</param>
        /// <param name="code">Type of the protocol message being sent.</param>
        /// <param name="data">Byte-field of the data, appropriate for the specific `code` used.</param>
        /// <param name="address">Ixian Wallet Address which triggered the event</param>
        /// <param name="helper_data">Optional, additional data to transmit after `data`.</param>
        /// <param name="skipEndpoint">If given, the message will not be sent to this remote endpoint. This prevents echoing the message to the originating node.</param>
        /// <returns>True, if at least one message was sent to at least one client.</returns>
        public static bool broadcastEventData(NetworkEvents.Type type, ProtocolMessageCode code, byte[] data, byte[] address, byte[] helper_data, RemoteEndpoint skipEndpoint = null)
        {
            bool result = false;

            try
            {
                QueueMessage queue_message = RemoteEndpoint.getQueueMessage(code, data, helper_data);
                lock (connectedClients)
                {
                    foreach (RemoteEndpoint endpoint in connectedClients)
                    {
                        if (skipEndpoint != null)
                        {
                            if (endpoint == skipEndpoint)
                            {
                                continue;
                            }
                        }

                        if (!endpoint.isConnected())
                        {
                            continue;
                        }

                        if (endpoint.helloReceived == false)
                        {
                            continue;
                        }

                        if (endpoint.presenceAddress == null || (endpoint.presenceAddress.type != 'C' && endpoint.presenceAddress.type != 'R'))
                        {
                            continue;
                        }

                        // Finally, check if the endpoint is subscribed to this event and address
                        if (endpoint.isSubscribedToAddress(type, address))
                        {
                            endpoint.sendData(queue_message);
                            result = true;
                        }
                    }
                }
            }catch (Exception e)
            {
                Logging.error("Exception occured in NetworkServer.broadcastEventData: " + e);
            }

            return(result);
        }
Ejemplo n.º 8
0
        /// <summary>
        ///  Prepares (serializes) a protocol message from the given Ixian message code and appropriate data. Checksum can be supplied, but
        ///  if it isn't, this function will calculate it using the default method.
        /// </summary>
        /// <remarks>
        ///  This function can be used from the server and client side.
        ///  Please note: This function does not validate that the payload `data` conforms to the expected message for `code`. It is the
        ///  caller's job to ensure that.
        /// </remarks>
        /// <param name="code">Message code.</param>
        /// <param name="data">Payload for the message.</param>
        /// <param name="checksum">Optional checksum. If not supplied, or if null, this function will calculate it with the default method.</param>
        /// <returns>Serialized message as a byte-field</returns>
        public static byte[] prepareProtocolMessage(ProtocolMessageCode code, byte[] data, byte[] checksum = null)
        {
            byte[] result = null;

            // Prepare the protocol sections
            int data_length = data.Length;

            if (data_length > CoreConfig.maxMessageSize)
            {
                Logging.error(String.Format("Tried to send data bigger than max allowed message size - {0} with code {1}.", data_length, code));
                return(null);
            }

            byte[] data_checksum = checksum;

            if (checksum == null)
            {
                data_checksum = Crypto.sha512sqTrunc(data, 0, 0, 32);
            }

            using (MemoryStream m = new MemoryStream(4096))
            {
                using (BinaryWriter writer = new BinaryWriter(m))
                {
                    // Protocol sections are code, length, checksum, data
                    // Write each section in binary, in that specific order
                    writer.Write((byte)'X');
                    writer.Write((int)code);
                    writer.Write(data_length);
                    writer.Write(data_checksum);

                    writer.Flush();
                    m.Flush();

                    byte header_checksum = getHeaderChecksum(m.ToArray());
                    writer.Write(header_checksum);

                    writer.Write((byte)'I');
                    writer.Write(data);
#if TRACE_MEMSTREAM_SIZES
                    Logging.info(String.Format("CoreProtocolMessage::prepareProtocolMessage: {0}", m.Length));
#endif
                }
                result = m.ToArray();
            }

            return(result);
        }
Ejemplo n.º 9
0
        /// <summary>
        ///  Prepares and broadcasts an Ixian protocol message to all connected nodes, filtered by `types`.
        /// </summary>
        /// <remarks>
        ///  The payload `data` should be properly formatted for the given `code` - this function will not ensure that this is so and
        ///  the caller must provide a valid message to this function.
        ///  The `skipEndpoint` parameter is useful when re-broadcasting a message received from a specific endpoint and do not wish to echo the same
        ///  data back to the sender.
        /// </remarks>
        /// <param name="types">Types of nodes to send this message to.</param>
        /// <param name="code">Protocol code.</param>
        /// <param name="data">Message payload</param>
        /// <param name="helper_data">Additional information, as required by the protocol message</param>
        /// <param name="skipEndpoint">Remote endpoint which should be skipped (data should not be sent to it).</param>
        /// <returns>True, if at least one message was sent to at least one other node. False if no messages were sent.</returns>
        public static bool broadcastProtocolMessage(char[] types, ProtocolMessageCode code, byte[] data, byte[] helper_data, RemoteEndpoint skipEndpoint = null)
        {
            if (data == null)
            {
                Logging.warn(string.Format("Invalid protocol message data for {0}", code));
                return(false);
            }

            bool c_result = NetworkClientManager.broadcastData(types, code, data, helper_data, skipEndpoint);
            bool s_result = NetworkServer.broadcastData(types, code, data, helper_data, skipEndpoint);

            if (!c_result && !s_result)
            {
                return(false);
            }

            return(true);
        }
Ejemplo n.º 10
0
 // 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");
 }
Ejemplo n.º 11
0
        // 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;
            }
        }
Ejemplo n.º 12
0
        /// <summary>
        ///  Sends the specified network message to the given address, if it is known and connected among clients.
        /// </summary>
        /// <param name="address">Ixian Wallet Address - the recipient of the message</param>
        /// <param name="code">Type of the network message to send</param>
        /// <param name="message">Byte-field with the required data, as specified by `code`.</param>
        /// <returns>True, if the message was delivered.</returns>
        public static bool forwardMessage(byte[] address, ProtocolMessageCode code, byte[] message)
        {
            if (address == null)
            {
                Logging.warn("Cannot forward message to null address.");
                return(false);
            }

            Logging.info(String.Format(">>>> Preparing to forward to {0}",
                                       Base58Check.Base58CheckEncoding.EncodePlain(address)));

            QueueMessage queue_message = RemoteEndpoint.getQueueMessage(code, message, null);

            lock (connectedClients)
            {
                foreach (RemoteEndpoint endpoint in connectedClients)
                {
                    // Skip connections without presence information
                    if (endpoint.presence == null)
                    {
                        continue;
                    }

                    // SKip disconnected endpoints
                    if (!endpoint.isConnected())
                    {
                        continue;
                    }

                    byte[] client_wallet = endpoint.presence.wallet;

                    if (client_wallet != null && address.SequenceEqual(client_wallet))
                    {
                        Logging.info(">>>> Forwarding message");
                        endpoint.sendData(queue_message);
                        return(true);
                    }
                }
            }


            return(false);
        }
Ejemplo n.º 13
0
        // Send data to all connected nodes
        // Returns true if the data was sent to at least one client
        public static bool broadcastData(char[] types, ProtocolMessageCode code, byte[] data, byte[] helper_data, RemoteEndpoint skipEndpoint = null)
        {
            bool         result        = false;
            QueueMessage queue_message = RemoteEndpoint.getQueueMessage(code, data, helper_data);

            lock (networkClients)
            {
                foreach (NetworkClient client in networkClients)
                {
                    if (skipEndpoint != null)
                    {
                        if (client == skipEndpoint)
                        {
                            continue;
                        }
                    }

                    if (!client.isConnected())
                    {
                        continue;
                    }

                    if (client.helloReceived == false)
                    {
                        continue;
                    }

                    if (types != null)
                    {
                        if (client.presenceAddress == null || !types.Contains(client.presenceAddress.type))
                        {
                            continue;
                        }
                    }


                    client.sendData(queue_message);
                    result = true;
                }
            }
            return(result);
        }
Ejemplo n.º 14
0
            // Sends event data to all subscribed clients
            public static bool broadcastEventData(NetworkEvents.Type type, ProtocolMessageCode code, byte[] data, byte[] address, byte[] helper_data, RemoteEndpoint skipEndpoint = null)
            {
                bool result = false;

                lock (connectedClients)
                {
                    foreach (RemoteEndpoint endpoint in connectedClients)
                    {
                        if (skipEndpoint != null)
                        {
                            if (endpoint == skipEndpoint)
                            {
                                continue;
                            }
                        }

                        if (!endpoint.isConnected())
                        {
                            continue;
                        }

                        if (endpoint.helloReceived == false)
                        {
                            continue;
                        }

                        if (endpoint.presenceAddress == null || endpoint.presenceAddress.type != 'C')
                        {
                            continue;
                        }

                        // Finally, check if the endpoint is subscribed to this event and address
                        if (endpoint.isSubscribedToEvent(type, address))
                        {
                            endpoint.sendData(code, data, helper_data);
                            result = true;
                        }
                    }
                }
                return(result);
            }
Ejemplo n.º 15
0
        /// <summary>
        ///  Sends the given data to all appropriate connected clients.
        /// </summary>
        /// <param name="types">Types of clients to which the data should be sent.</param>
        /// <param name="code">Type of the protocol message being sent.</param>
        /// <param name="data">Byte-field of the data, appropriate for the specific `code` used.</param>
        /// <param name="helper_data">Optional, additional data to transmit after `data`.</param>
        /// <param name="skipEndpoint">If given, the message will not be sent to this remote endpoint. This prevents echoing the message to the originating node.</param>
        /// <returns>True, if at least one message was sent to at least one client.</returns>
        public static bool broadcastData(char[] types, ProtocolMessageCode code, byte[] data, byte[] helper_data, RemoteEndpoint skipEndpoint = null)
        {
            bool result = false;

            lock (connectedClients)
            {
                foreach (RemoteEndpoint endpoint in connectedClients)
                {
                    if (skipEndpoint != null)
                    {
                        if (endpoint == skipEndpoint)
                        {
                            continue;
                        }
                    }

                    if (!endpoint.isConnected())
                    {
                        continue;
                    }

                    if (endpoint.helloReceived == false)
                    {
                        continue;
                    }

                    if (types != null)
                    {
                        if (endpoint.presenceAddress == null || !types.Contains(endpoint.presenceAddress.type))
                        {
                            continue;
                        }
                    }

                    endpoint.sendData(code, data, helper_data);
                    result = true;
                }
            }
            return(result);
        }
Ejemplo n.º 16
0
        // Sends data over the network
        public void sendData(ProtocolMessageCode code, byte[] data, byte[] helper_data = null)
        {
            if (data == null)
            {
                Logging.warn(string.Format("Invalid protocol message data for {0}", code));
                return;
            }

            QueueMessage message = new QueueMessage();

            message.code         = code;
            message.data         = data;
            message.checksum     = Crypto.sha512sqTrunc(data, 0, 0, 32);
            message.skipEndpoint = null;
            message.helperData   = helper_data;

            if (code == ProtocolMessageCode.bye || code == ProtocolMessageCode.keepAlivePresence ||
                code == ProtocolMessageCode.getPresence || code == ProtocolMessageCode.updatePresence)
            {
                lock (sendQueueMessagesHighPriority)
                {
                    addMessageToSendQueue(sendQueueMessagesHighPriority, message);
                }
            }
            else if (code != ProtocolMessageCode.transactionData && code != ProtocolMessageCode.newTransaction)
            {
                lock (sendQueueMessagesNormalPriority)
                {
                    addMessageToSendQueue(sendQueueMessagesNormalPriority, message);
                }
            }
            else
            {
                lock (sendQueueMessagesLowPriority)
                {
                    addMessageToSendQueue(sendQueueMessagesLowPriority, message);
                }
            }
        }
Ejemplo n.º 17
0
        /// <summary>
        ///  Sends the protocol message to the specified neighbor node, given as a Hostname or IP address and port.
        /// </summary>
        /// <param name="neighbor">IP address or hostname and port for the neighbor.</param>
        /// <param name="code">Type of the protocol message</param>
        /// <param name="data">Data required by the protocol message `code`.</param>
        /// <param name="helper_data">Optional, additional data to transmit after `data`.</param>
        /// <returns>True if the data was sent to the specified neighbor.</returns>
        public static bool sendToClient(string neighbor, ProtocolMessageCode code, byte[] data, byte[] helper_data)
        {
            RemoteEndpoint client = null;

            lock (connectedClients)
            {
                foreach (RemoteEndpoint ep in connectedClients)
                {
                    if (ep.getFullAddress() == neighbor)
                    {
                        client = ep;
                        break;
                    }
                }
            }
            if (client != null)
            {
                client.sendData(code, data, helper_data);
                return(true);
            }
            return(false);
        }
        public static bool sendToClient(string neighbor, ProtocolMessageCode code, byte[] data, byte[] helper_data)
        {
            NetworkClient client = null;

            lock (networkClients)
            {
                foreach (NetworkClient c in networkClients)
                {
                    if (c.getFullAddress() == neighbor)
                    {
                        client = c;
                        break;
                    }
                }
            }

            if (client != null)
            {
                client.sendData(code, data, helper_data);
                return(true);
            }

            return(false);
        }
Ejemplo n.º 19
0
        public static bool addToInventory(char[] types, InventoryItem item, RemoteEndpoint skip_endpoint, ProtocolMessageCode code, byte[] data, byte[] helper)
        {
            QueueMessage queue_message = RemoteEndpoint.getQueueMessage(code, data, helper);

            lock (connectedClients)
            {
                foreach (var client in connectedClients)
                {
                    try
                    {
                        if (!client.isConnected() || !client.helloReceived)
                        {
                            continue;
                        }
                        if (client == skip_endpoint)
                        {
                            continue;
                        }
                        if (!types.Contains(client.presenceAddress.type))
                        {
                            continue;
                        }
                        if (client.version > 5)
                        {
                            client.addInventoryItem(item);
                        }
                        else
                        {
                            // TODO legacy, can be removed after network upgrades
                            client.sendData(queue_message);
                        }
                    }catch (Exception e)
                    {
                        Logging.error("Exception occured in NetworkServer.addToInventory: " + e);
                    }
                }
            }
            return(true);
        }
        // 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))
                            {
                                byte[] challenge_response = null;

                                int    challenge_len = reader.ReadInt32();
                                byte[] challenge     = reader.ReadBytes(challenge_len);

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

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

                                if (endpoint.presenceAddress.type == 'M')
                                {
                                    Node.setNetworkBlock(last_block_num, block_checksum, block_version);

                                    // Get random presences
                                    endpoint.sendData(ProtocolMessageCode.getRandomPresences, new byte[1] {
                                        (byte)'M'
                                    });

                                    CoreProtocolMessage.subscribeToEvents(endpoint);
                                }
                            }
                        }
                    }
                    break;

                case ProtocolMessageCode.balance:
                {
                    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()))
                            {
                                // Retrieve the blockheight for the balance
                                ulong block_height = reader.ReadUInt64();

                                if (block_height > Node.balance.blockHeight && (Node.balance.balance != balance || Node.balance.blockHeight == 0))
                                {
                                    byte[] block_checksum = reader.ReadBytes(reader.ReadInt32());

                                    Node.balance.address       = address;
                                    Node.balance.balance       = balance;
                                    Node.balance.blockHeight   = block_height;
                                    Node.balance.blockChecksum = block_checksum;
                                    Node.balance.verified      = false;
                                }
                            }
                        }
                    }
                }
                break;

                case ProtocolMessageCode.updatePresence:
                {
                    // Parse the data and update entries in the presence list
                    PresenceList.updateFromBytes(data);
                }
                break;

                case ProtocolMessageCode.blockHeaders:
                {
                    // Forward the block headers to the TIV handler
                    Node.tiv.receivedBlockHeaders(data, endpoint);
                }
                break;

                case ProtocolMessageCode.pitData:
                {
                    Node.tiv.receivedPIT(data, endpoint);
                }
                break;

                case ProtocolMessageCode.newTransaction:
                case ProtocolMessageCode.transactionData:
                {
                    Transaction tx = new Transaction(data, true);

                    PendingTransactions.increaseReceivedCount(tx.id);

                    Node.tiv.receivedNewTransaction(tx);
                    Console.WriteLine("Received new transaction {0}", tx.id);
                }
                break;

                default:
                    break;
                }
            }
            catch (Exception e)
            {
                Logging.error(string.Format("Error parsing network message. Details: {0}", e.ToString()));
            }

            if (waitingFor == code)
            {
                blocked = false;
            }
        }
Ejemplo n.º 21
0
        // 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))
                        {
                            CoreProtocolMessage.processHelloMessageV6(endpoint, reader);
                        }
                    }
                }
                break;


                case ProtocolMessageCode.helloData:
                    using (MemoryStream m = new MemoryStream(data))
                    {
                        using (BinaryReader reader = new BinaryReader(m))
                        {
                            if (!CoreProtocolMessage.processHelloMessageV6(endpoint, reader))
                            {
                                return;
                            }

                            ulong  last_block_num = reader.ReadIxiVarUInt();
                            int    bcLen          = (int)reader.ReadIxiVarUInt();
                            byte[] block_checksum = reader.ReadBytes(bcLen);

                            endpoint.blockHeight = last_block_num;

                            int block_version = (int)reader.ReadIxiVarUInt();

                            if (endpoint.presenceAddress.type != 'C')
                            {
                                ulong highest_block_height = IxianHandler.getHighestKnownNetworkBlockHeight();
                                if (last_block_num + 10 < 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
                            endpoint.helloReceived = true;
                            NetworkClientManager.recalculateLocalTimeDifference();

                            if (endpoint.presenceAddress.type == 'R')
                            {
                                string[] connected_servers = StreamClientManager.getConnectedClients(true);
                                if (connected_servers.Count() == 1 || !connected_servers.Contains(StreamClientManager.primaryS2Address))
                                {
                                    if (StreamClientManager.primaryS2Address == "")
                                    {
                                        FriendList.requestAllFriendsPresences();
                                    }
                                    // TODO set the primary s2 host more efficiently, perhaps allow for multiple s2 primary hosts
                                    StreamClientManager.primaryS2Address = endpoint.getFullAddress(true);
                                    // TODO TODO do not set if directly connectable
                                    IxianHandler.publicIP           = endpoint.address;
                                    IxianHandler.publicPort         = endpoint.incomingPort;
                                    PresenceList.forceSendKeepAlive = true;
                                    Logging.info("Forcing KA from networkprotocol");
                                }
                            }
                            else if (endpoint.presenceAddress.type == 'C')
                            {
                                Friend f = FriendList.getFriend(endpoint.presence.wallet);
                                if (f != null && f.bot)
                                {
                                    StreamProcessor.sendGetBotInfo(f);
                                }
                            }

                            if (endpoint.presenceAddress.type == 'M' || endpoint.presenceAddress.type == 'H')
                            {
                                Node.setNetworkBlock(last_block_num, block_checksum, block_version);

                                // Get random presences
                                endpoint.sendData(ProtocolMessageCode.getRandomPresences, new byte[1] {
                                    (byte)'R'
                                });
                                endpoint.sendData(ProtocolMessageCode.getRandomPresences, new byte[1] {
                                    (byte)'M'
                                });
                                endpoint.sendData(ProtocolMessageCode.getRandomPresences, new byte[1] {
                                    (byte)'H'
                                });

                                subscribeToEvents(endpoint);
                            }
                        }
                    }
                    break;

                case ProtocolMessageCode.s2data:
                {
                    StreamProcessor.receiveData(data, endpoint);
                }
                break;

                case ProtocolMessageCode.updatePresence:
                {
                    Logging.info("NET: Receiving presence list update");
                    // Parse the data and update entries in the presence list
                    Presence p = PresenceList.updateFromBytes(data);
                    if (p == null)
                    {
                        return;
                    }

                    Friend f = FriendList.getFriend(p.wallet);
                    if (f != null)
                    {
                        f.relayIP = p.addresses[0].address;
                    }
                }
                break;

                case ProtocolMessageCode.keepAlivePresence:
                {
                    byte[]   address   = null;
                    long     last_seen = 0;
                    byte[]   device_id = null;
                    bool     updated   = PresenceList.receiveKeepAlive(data, out address, out last_seen, out device_id, endpoint);
                    Presence p         = PresenceList.getPresenceByAddress(address);
                    if (p == null)
                    {
                        return;
                    }

                    Friend f = FriendList.getFriend(p.wallet);
                    if (f != null)
                    {
                        f.relayIP = p.addresses[0].address;
                    }
                }
                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.getPresence2:
                {
                    using (MemoryStream m = new MemoryStream(data))
                    {
                        using (BinaryReader reader = new BinaryReader(m))
                        {
                            int    walletLen = (int)reader.ReadIxiVarUInt();
                            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:
                {
                    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()))
                            {
                                // Retrieve the blockheight for the balance
                                ulong block_height = reader.ReadUInt64();

                                if (block_height > Node.balance.blockHeight && (Node.balance.balance != balance || Node.balance.blockHeight == 0))
                                {
                                    byte[] block_checksum = reader.ReadBytes(reader.ReadInt32());

                                    Node.balance.address       = address;
                                    Node.balance.balance       = balance;
                                    Node.balance.blockHeight   = block_height;
                                    Node.balance.blockChecksum = block_checksum;
                                    Node.balance.verified      = false;
                                }
                                Node.balance.lastUpdate = Clock.getTimestamp();
                            }
                        }
                    }
                }
                break;

                case ProtocolMessageCode.balance2:
                {
                    using (MemoryStream m = new MemoryStream(data))
                    {
                        using (BinaryReader reader = new BinaryReader(m))
                        {
                            int    address_length = (int)reader.ReadIxiVarUInt();
                            byte[] address        = reader.ReadBytes(address_length);

                            // Retrieve the latest balance
                            IxiNumber balance = new IxiNumber(new BigInteger(reader.ReadBytes((int)reader.ReadIxiVarUInt())));

                            if (address.SequenceEqual(Node.walletStorage.getPrimaryAddress()))
                            {
                                // Retrieve the blockheight for the balance
                                ulong block_height = reader.ReadIxiVarUInt();

                                if (block_height > Node.balance.blockHeight && (Node.balance.balance != balance || Node.balance.blockHeight == 0))
                                {
                                    byte[] block_checksum = reader.ReadBytes((int)reader.ReadIxiVarUInt());

                                    Node.balance.address       = address;
                                    Node.balance.balance       = balance;
                                    Node.balance.blockHeight   = block_height;
                                    Node.balance.blockChecksum = block_checksum;
                                    Node.balance.verified      = false;
                                }
                                Node.balance.lastUpdate = Clock.getTimestamp();
                            }
                        }
                    }
                }
                break;

                case ProtocolMessageCode.newTransaction:
                case ProtocolMessageCode.transactionData:
                {
                    // TODO: check for errors/exceptions
                    Transaction transaction = new Transaction(data, true);

                    if (endpoint.presenceAddress.type == 'M' || endpoint.presenceAddress.type == 'H')
                    {
                        PendingTransactions.increaseReceivedCount(transaction.id, endpoint.presence.wallet);
                    }

                    TransactionCache.addUnconfirmedTransaction(transaction);

                    Node.tiv.receivedNewTransaction(transaction);
                }
                break;

                case ProtocolMessageCode.bye:
                    CoreProtocolMessage.processBye(data, endpoint);
                    break;

                case ProtocolMessageCode.blockHeaders2:
                {
                    // Forward the block headers to the TIV handler
                    Node.tiv.receivedBlockHeaders2(data, endpoint);
                }
                break;

                case ProtocolMessageCode.pitData2:
                {
                    Node.tiv.receivedPIT2(data, endpoint);
                }
                break;

                default:
                    break;
                }
            }
            catch (Exception e)
            {
                Logging.error("Error parsing network message. Details: {0}", e.ToString());
            }
        }
Ejemplo n.º 22
0
        // 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))
                        {
                            bool processed = false;
                            processed = CoreProtocolMessage.processHelloMessageV6(endpoint, reader, false);

                            if (!processed || (Config.whiteList.Count > 0 && !Config.whiteList.Contains(endpoint.presence.wallet, new ByteArrayComparer())))
                            {
                                CoreProtocolMessage.sendBye(endpoint, ProtocolByeCode.bye, string.Format("Access denied."), "", true);
                                return;
                            }

                            endpoint.helloReceived = true;
                        }
                    }
                    break;


                case ProtocolMessageCode.helloData:
                    using (MemoryStream m = new MemoryStream(data))
                    {
                        using (BinaryReader reader = new BinaryReader(m))
                        {
                            if (CoreProtocolMessage.processHelloMessageV6(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.ReadIxiVarUInt();

                                int    bcLen          = (int)reader.ReadIxiVarUInt();
                                byte[] block_checksum = reader.ReadBytes(bcLen);

                                endpoint.blockHeight = last_block_num;

                                int block_version = (int)reader.ReadIxiVarUInt();

                                try
                                {
                                    string public_ip = reader.ReadString();
                                    ((NetworkClient)endpoint).myAddress = public_ip;
                                }
                                catch (Exception)
                                {
                                }

                                string address = NetworkClientManager.getMyAddress();
                                if (address != null)
                                {
                                    if (IxianHandler.publicIP != address)
                                    {
                                        Logging.info("Setting public IP to " + address);
                                        IxianHandler.publicIP = address;
                                    }
                                }

                                // Process the hello data
                                endpoint.helloReceived = true;
                                NetworkClientManager.recalculateLocalTimeDifference();

                                Node.setNetworkBlock(last_block_num, block_checksum, block_version);

                                // Get random presences
                                endpoint.sendData(ProtocolMessageCode.getRandomPresences, new byte[1] {
                                    (byte)'M'
                                });
                                endpoint.sendData(ProtocolMessageCode.getRandomPresences, new byte[1] {
                                    (byte)'H'
                                });

                                CoreProtocolMessage.subscribeToEvents(endpoint);
                            }
                        }
                    }
                    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.transactionData:
                {
                    Transaction tx = new Transaction(data, true);

                    if (endpoint.presenceAddress.type == 'M' || endpoint.presenceAddress.type == 'H')
                    {
                        PendingTransactions.increaseReceivedCount(tx.id, endpoint.presence.wallet);
                    }

                    Node.tiv.receivedNewTransaction(tx);
                    Logging.info("Received new transaction {0}", tx.id);

                    Node.addTransactionToActivityStorage(tx);
                }
                break;

                case ProtocolMessageCode.updatePresence:
                {
                    // Parse the data and update entries in the presence list
                    PresenceList.updateFromBytes(data, 0);
                }
                break;


                case ProtocolMessageCode.keepAlivePresence:
                {
                    byte[] address   = null;
                    long   last_seen = 0;
                    byte[] device_id = null;
                    bool   updated   = PresenceList.receiveKeepAlive(data, out address, out last_seen, out device_id, 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.getPresence2:
                {
                    using (MemoryStream m = new MemoryStream(data))
                    {
                        using (BinaryReader reader = new BinaryReader(m))
                        {
                            int      walletLen = (int)reader.ReadIxiVarUInt();
                            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:
                {
                    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(IxianHandler.getWalletStorage().getPrimaryAddress()))
                            {
                                // Retrieve the blockheight for the balance
                                ulong block_height = reader.ReadUInt64();

                                if (block_height > Node.balance.blockHeight && (Node.balance.balance != balance || Node.balance.blockHeight == 0))
                                {
                                    byte[] block_checksum = reader.ReadBytes(reader.ReadInt32());

                                    Node.balance.address       = address;
                                    Node.balance.balance       = balance;
                                    Node.balance.blockHeight   = block_height;
                                    Node.balance.blockChecksum = block_checksum;
                                    Node.balance.lastUpdate    = Clock.getTimestamp();
                                    Node.balance.verified      = false;
                                }
                            }
                        }
                    }
                }
                break;

                case ProtocolMessageCode.balance2:
                {
                    using (MemoryStream m = new MemoryStream(data))
                    {
                        using (BinaryReader reader = new BinaryReader(m))
                        {
                            int    address_length = (int)reader.ReadIxiVarUInt();
                            byte[] address        = reader.ReadBytes(address_length);

                            // Retrieve the latest balance
                            IxiNumber balance = new IxiNumber(new BigInteger(reader.ReadBytes((int)reader.ReadIxiVarUInt())));

                            if (address.SequenceEqual(IxianHandler.getWalletStorage().getPrimaryAddress()))
                            {
                                // Retrieve the blockheight for the balance
                                ulong block_height = reader.ReadIxiVarUInt();

                                if (block_height > Node.balance.blockHeight && (Node.balance.balance != balance || Node.balance.blockHeight == 0))
                                {
                                    byte[] block_checksum = reader.ReadBytes((int)reader.ReadIxiVarUInt());

                                    Node.balance.address       = address;
                                    Node.balance.balance       = balance;
                                    Node.balance.blockHeight   = block_height;
                                    Node.balance.blockChecksum = block_checksum;
                                    Node.balance.lastUpdate    = Clock.getTimestamp();
                                    Node.balance.verified      = false;
                                }
                            }
                        }
                    }
                }
                break;

                case ProtocolMessageCode.bye:
                    CoreProtocolMessage.processBye(data, endpoint);
                    break;

                case ProtocolMessageCode.blockHeaders2:
                {
                    // Forward the block headers to the TIV handler
                    Node.tiv.receivedBlockHeaders2(data, endpoint);
                }
                break;

                case ProtocolMessageCode.pitData2:
                {
                    Node.tiv.receivedPIT2(data, endpoint);
                }
                break;

                default:
                    break;
                }
            }
            catch (Exception e)
            {
                Logging.error(string.Format("Error parsing network message. Details: {0}", e.ToString()));
            }
        }
Ejemplo n.º 23
0
 public static void parseProtocolMessage(ProtocolMessageCode code, byte[] data, RemoteEndpoint endpoint)
 {
     verifyHandler();
     handlerClass.parseProtocolMessage(code, data, endpoint);
 }
Ejemplo n.º 24
0
        // 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:
                    handleHello(data, endpoint);
                    break;

                case ProtocolMessageCode.helloData:
                    handleHelloData(data, endpoint);
                    break;

                case ProtocolMessageCode.s2data:
                    StreamProcessor.receiveData(data, endpoint);
                    break;

                case ProtocolMessageCode.s2failed:
                    Logging.error("Failed to send s2 data");
                    break;

                case ProtocolMessageCode.s2signature:
                    StreamProcessor.receivedTransactionSignature(data, endpoint);
                    break;

                case ProtocolMessageCode.newTransaction:
                case ProtocolMessageCode.transactionData:
                {
                    Transaction tx = new Transaction(data, true);

                    if (endpoint.presenceAddress.type == 'M' || endpoint.presenceAddress.type == 'H')
                    {
                        PendingTransactions.increaseReceivedCount(tx.id, endpoint.presence.wallet);
                    }

                    Node.tiv.receivedNewTransaction(tx);
                    Logging.info("Received new transaction {0}", tx.id);

                    Node.addTransactionToActivityStorage(tx);
                }
                break;

                case ProtocolMessageCode.updatePresence:
                    // Parse the data and update entries in the presence list
                    PresenceList.updateFromBytes(data);
                    break;

                case ProtocolMessageCode.keepAlivePresence:
                    byte[] address   = null;
                    long   last_seen = 0;
                    byte[] device_id = null;
                    bool   updated   = PresenceList.receiveKeepAlive(data, out address, out last_seen, out device_id, endpoint);
                    break;

                case ProtocolMessageCode.getPresence:
                    handleGetPresence(data, endpoint);
                    break;

                case ProtocolMessageCode.getPresence2:
                    handleGetPresence2(data, endpoint);
                    break;

                case ProtocolMessageCode.balance:
                    handleBalance(data, endpoint);
                    break;

                case ProtocolMessageCode.balance2:
                    handleBalance2(data, endpoint);
                    break;

                case ProtocolMessageCode.bye:
                    CoreProtocolMessage.processBye(data, endpoint);
                    break;

                case ProtocolMessageCode.blockHeaders2:
                    // Forward the block headers to the TIV handler
                    Node.tiv.receivedBlockHeaders2(data, endpoint);
                    break;

                case ProtocolMessageCode.pitData2:
                    Node.tiv.receivedPIT2(data, endpoint);
                    break;

                default:
                    break;
                }
            }
            catch (Exception e)
            {
                Logging.error(string.Format("Error parsing network message. Details: {0}", e.ToString()));
            }
        }
Ejemplo n.º 25
0
 public override void parseProtocolMessage(ProtocolMessageCode code, byte[] data, RemoteEndpoint endpoint)
 {
     ProtocolMessage.parseProtocolMessage(code, data, endpoint);
 }
Ejemplo n.º 26
0
 public static void setWaitFor(ProtocolMessageCode value)
 {
     waitingFor = value;
     blocked    = true;
 }
Ejemplo n.º 27
0
 public abstract void parseProtocolMessage(ProtocolMessageCode code, byte[] data, RemoteEndpoint endpoint);
Ejemplo n.º 28
0
        // Broadcasts protocol message to a single random node with block height higher than the one specified with parameter block_num
        /// <summary>
        ///  Sends the specified protocol message to one of the connected remote endpoints, chosen randomly.
        /// </summary>
        /// <remarks>
        ///  The payload `data` should be properly formatted for the given `code` - this function will not ensure that this is so and
        ///  the caller must provide a valid message to this function.
        ///  The `skipEndpoint` parameter is useful when re-broadcasting a message received from a specific endpoint and do not wish to echo the same
        ///  data back to the sender.
        ///  The `block_num` parameter is used to filter the remote endpoints based on their latest known block height.
        /// </remarks>
        /// <param name="types">Types of the nodes where the message should be sent.</param>
        /// <param name="code">Ixian protocol code.</param>
        /// <param name="data">Payload data.</param>
        /// <param name="block_num">Block which should be searched for the endpoint addresses.</param>
        /// <param name="skipEndpoint">Minimum block height for endpoints which should receive this message.</param>
        /// <returns>True, if at least one message was sent to at least one remote endpoint. False if no messages were sent.</returns>
        public static bool broadcastProtocolMessageToSingleRandomNode(char[] types, ProtocolMessageCode code, byte[] data, ulong block_num, RemoteEndpoint skipEndpoint = null)
        {
            if (data == null)
            {
                Logging.warn(string.Format("Invalid protocol message data for {0}", code));
                return(false);
            }

            lock (NetworkClientManager.networkClients)
            {
                lock (NetworkServer.connectedClients)
                {
                    int serverCount = 0;
                    int clientCount = 0;
                    List <NetworkClient>  servers = null;
                    List <RemoteEndpoint> clients = null;

                    if (types == null)
                    {
                        servers = NetworkClientManager.networkClients.FindAll(x => x.blockHeight > block_num && x.isConnected() && x.helloReceived);
                        clients = NetworkServer.connectedClients.FindAll(x => x.blockHeight > block_num && x.isConnected() && x.helloReceived);

                        serverCount = servers.Count();
                        clientCount = clients.Count();

                        if (serverCount == 0 && clientCount == 0)
                        {
                            servers = NetworkClientManager.networkClients.FindAll(x => x.blockHeight == block_num && x.isConnected() && x.helloReceived);
                            clients = NetworkServer.connectedClients.FindAll(x => x.blockHeight == block_num && x.isConnected() && x.helloReceived);
                        }
                    }
                    else
                    {
                        servers = NetworkClientManager.networkClients.FindAll(x => x.blockHeight > block_num && x.presenceAddress != null && types.Contains(x.presenceAddress.type) && x.isConnected() && x.helloReceived);
                        clients = NetworkServer.connectedClients.FindAll(x => x.blockHeight > block_num && x.presenceAddress != null && types.Contains(x.presenceAddress.type) && x.isConnected() && x.helloReceived);

                        serverCount = servers.Count();
                        clientCount = clients.Count();

                        if (serverCount == 0 && clientCount == 0)
                        {
                            servers = NetworkClientManager.networkClients.FindAll(x => x.blockHeight == block_num && x.presenceAddress != null && types.Contains(x.presenceAddress.type) && x.isConnected() && x.helloReceived);
                            clients = NetworkServer.connectedClients.FindAll(x => x.blockHeight == block_num && x.presenceAddress != null && types.Contains(x.presenceAddress.type) && x.isConnected() && x.helloReceived);
                        }
                    }

                    serverCount = servers.Count();
                    clientCount = clients.Count();

                    if (serverCount == 0 && clientCount == 0)
                    {
                        return(false);
                    }

                    Random r    = new Random();
                    int    rIdx = r.Next(serverCount + clientCount);

                    RemoteEndpoint re = null;

                    if (rIdx < serverCount)
                    {
                        re = servers[rIdx];
                    }
                    else
                    {
                        re = clients[rIdx - serverCount];
                    }

                    if (re == skipEndpoint && serverCount + clientCount > 1)
                    {
                        if (rIdx + 1 < serverCount)
                        {
                            re = servers[rIdx + 1];
                        }
                        else if (rIdx + 1 < serverCount + clientCount)
                        {
                            re = clients[rIdx + 1 - serverCount];
                        }
                        else if (serverCount > 0)
                        {
                            re = servers[0];
                        }
                        else if (clientCount > 0)
                        {
                            re = clients[0];
                        }
                    }

                    if (re != null && re.isConnected())
                    {
                        re.sendData(code, data);
                        return(true);
                    }
                    return(false);
                }
            }
        }
Ejemplo n.º 29
0
        // 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()));
            }
        }
Ejemplo n.º 30
0
        public static void receiveProtocolMessage(ProtocolMessageCode code, byte[] data, uint checksum, MessagePriority priority, RemoteEndpoint endpoint)
        {
            QueueMessageRecv message = new QueueMessageRecv
            {
                code       = code,
                data       = data,
                length     = data.Length,
                checksum   = checksum,
                endpoint   = endpoint,
                helperData = extractHelperData(code, data)
            };

            if (priority == MessagePriority.medium)
            {
                lock (queueMediumPriority)
                {
                    if (message.helperData != null)
                    {
                        if (queueMediumPriority.Exists(x => x.code == message.code && x.helperData.SequenceEqual(message.helperData)))
                        {
                            int msg_index = queueMediumPriority.FindIndex(x => x.code == message.code && message.helperData.SequenceEqual(x.helperData));
                            if (queueMediumPriority[msg_index].length < message.length)
                            {
                                queueMediumPriority[msg_index] = message;
                            }
                            return;
                        }
                    }

                    if (queueMediumPriority.Exists(x => x.code == message.code && x.checksum == message.checksum))
                    {
                        Logging.trace("Attempting to add a duplicate message (code: {0}) to the network queue", code);
                        return;
                    }

                    queueMediumPriority.Add(message);
                }
                return;
            }

            lock (queueLowPriority)
            {
                // Move block related messages to txqueue
                bool found_get_request = false;
                bool found_tx_request  = false;
                switch (code)
                {
#pragma warning disable CS0618 // Type or member is obsolete
                case ProtocolMessageCode.getTransaction:
                case ProtocolMessageCode.getTransaction2:
                case ProtocolMessageCode.getTransaction3:
                case ProtocolMessageCode.getTransactions:
                case ProtocolMessageCode.getTransactions2:
                case ProtocolMessageCode.getBlock:
                case ProtocolMessageCode.getBlock2:
                case ProtocolMessageCode.getBlock3:
                case ProtocolMessageCode.getBlockHeaders:
                case ProtocolMessageCode.getBlockHeaders2:
                case ProtocolMessageCode.getSignatures:
                case ProtocolMessageCode.getBlockSignatures2:
                case ProtocolMessageCode.getPIT:
                case ProtocolMessageCode.getPIT2:
#pragma warning restore CS0618 // Type or member is obsolete
                    found_get_request = true;
                    found_tx_request  = true;
                    break;

#pragma warning disable CS0618 // Type or member is obsolete
                case ProtocolMessageCode.transactionsChunk:
                case ProtocolMessageCode.transactionsChunk2:
                case ProtocolMessageCode.newTransaction:
                case ProtocolMessageCode.transactionData:
                case ProtocolMessageCode.blockTransactionsChunk:
                case ProtocolMessageCode.blockHeaders:
                case ProtocolMessageCode.blockHeaders2:
                case ProtocolMessageCode.newBlock:
                case ProtocolMessageCode.blockData:
                case ProtocolMessageCode.pitData:
                case ProtocolMessageCode.pitData2:
                case ProtocolMessageCode.inventory:
                case ProtocolMessageCode.inventory2:
#pragma warning restore CS0618 // Type or member is obsolete
                    found_get_request = false;
                    found_tx_request  = true;
                    break;
                }
                if (found_tx_request)
                {
                    if (found_get_request)
                    {
                        if (message.helperData != null)
                        {
                            if (queueLowPriority.Exists(x => x.code == message.code && x.helperData.SequenceEqual(message.helperData) && x.endpoint == message.endpoint))
                            {
                                int msg_index = queueLowPriority.FindIndex(x => x.code == message.code && message.helperData.SequenceEqual(x.helperData));
                                if (queueLowPriority[msg_index].length < message.length)
                                {
                                    queueLowPriority[msg_index] = message;
                                }
                                return;
                            }
                        }

                        if (queueLowPriority.Exists(x => x.code == message.code && x.checksum == message.checksum && x.endpoint == message.endpoint))
                        {
                            Logging.trace("Attempting to add a duplicate message (code: {0}) to the network queue", code);
                            return;
                        }
                    }
                    else
                    {
                        if (message.helperData != null)
                        {
                            if (queueLowPriority.Exists(x => x.code == message.code && x.helperData.SequenceEqual(message.helperData)))
                            {
                                int msg_index = queueLowPriority.FindIndex(x => x.code == message.code && message.helperData.SequenceEqual(x.helperData));
                                if (queueLowPriority[msg_index].length < message.length)
                                {
                                    queueLowPriority[msg_index] = message;
                                }
                                return;
                            }
                        }

                        if (queueLowPriority.Exists(x => x.code == message.code && x.checksum == message.checksum))
                        {
                            Logging.trace("Attempting to add a duplicate message (code: {0}) to the network queue", code);
                            return;
                        }
                    }

                    bool add = true;
                    if (queueLowPriority.Count > 20)
                    {
                        switch (code)
                        {
#pragma warning disable CS0618 // Type or member is obsolete
                        case ProtocolMessageCode.getTransaction:
                        case ProtocolMessageCode.getTransaction2:
                        case ProtocolMessageCode.getTransaction3:
                        case ProtocolMessageCode.getTransactions:
                        case ProtocolMessageCode.getTransactions2:
                        case ProtocolMessageCode.getBlock:
                        case ProtocolMessageCode.getBlock2:
                        case ProtocolMessageCode.getBlock3:
                        case ProtocolMessageCode.getBlockHeaders:
                        case ProtocolMessageCode.getBlockHeaders2:
                        case ProtocolMessageCode.newBlock:
                        case ProtocolMessageCode.blockData:
                        case ProtocolMessageCode.getSignatures:
                        case ProtocolMessageCode.getBlockSignatures2:
                        case ProtocolMessageCode.getPIT:
                        case ProtocolMessageCode.getPIT2:
                        case ProtocolMessageCode.inventory:
                        case ProtocolMessageCode.inventory2:
#pragma warning restore CS0618 // Type or member is obsolete
                        {
                            queueLowPriority.Insert(5, message);
                            add = false;
                            break;
                        }
                        }
                    }
                    if (add)
                    {
                        // Add it to the tx queue
                        queueLowPriority.Add(message);
                    }
                    return;
                }
            }

            lock (queueHighPriority)
            {
                // ignore duplicates
                if (queueHighPriority.Exists(x => x.code == message.code && x.checksum == message.checksum && x.endpoint == message.endpoint))
                {
                    Logging.trace("Attempting to add a duplicate message (code: {0}) to the network queue", code);
                    return;
                }

                // Handle normal messages, but prioritize block-related messages
                switch (code)
                {
                case ProtocolMessageCode.bye:
                case ProtocolMessageCode.hello:
                case ProtocolMessageCode.helloData:
                    queueHighPriority.Insert(0, message);
                    return;

                case ProtocolMessageCode.keepAlivePresence:
                case ProtocolMessageCode.getPresence:
                case ProtocolMessageCode.getPresence2:
                case ProtocolMessageCode.updatePresence:
                    // Prioritize if queue is large
                    if (queueHighPriority.Count > 10)
                    {
                        queueHighPriority.Insert(5, message);
                        return;
                    }

                    break;
                }

                // Add it to the normal queue
                queueHighPriority.Add(message);
            }
        }