コード例 #1
0
ファイル: NetworkServer.cs プロジェクト: radevman/Ixian-Core
        private static void acceptConnection(Socket clientSocket)
        {
            IPEndPoint clientEndpoint = (IPEndPoint)clientSocket.RemoteEndPoint;

            // Add timeouts and set socket options
            //clientSocket.ReceiveTimeout = 5000;
            //clientSocket.SendTimeout = 5000;
            clientSocket.LingerState = new LingerOption(true, 3);
            clientSocket.NoDelay     = true;
            clientSocket.Blocking    = true;

            if (!IxianHandler.isAcceptingConnections())
            {
                Thread.Sleep(100); // wait a bit for check connectivity purposes
                clientSocket.Send(CoreProtocolMessage.prepareProtocolMessage(ProtocolMessageCode.bye, new byte[1]));
                clientSocket.Shutdown(SocketShutdown.Both);
                clientSocket.Disconnect(true);
                return;
            }

            lastIncomingConnectionTime = DateTime.UtcNow;
            connectable = true;

            // Setup the remote endpoint
            RemoteEndpoint remoteEndpoint = new RemoteEndpoint();

            lock (connectedClients)
            {
                if (connectedClients.Count + 1 > CoreConfig.maximumServerMasterNodes)
                {
                    Logging.warn(string.Format("Maximum number of connected clients reached. Disconnecting client: {0}:{1}",
                                               clientEndpoint.Address.ToString(), clientEndpoint.Port));
                    clientSocket.Send(CoreProtocolMessage.prepareProtocolMessage(ProtocolMessageCode.bye, new byte[1]));
                    clientSocket.Shutdown(SocketShutdown.Both);
                    clientSocket.Disconnect(true);
                    return;
                }

                var existing_clients = connectedClients.Where(re => re.remoteIP.Address == clientEndpoint.Address);
                if (existing_clients.Count() > 0)
                {
                    Logging.warn(String.Format("Client {0}:{1} already connected as {2}.",
                                               clientEndpoint.Address.ToString(), clientEndpoint.Port, existing_clients.First().ToString()));
                    clientSocket.Send(CoreProtocolMessage.prepareProtocolMessage(ProtocolMessageCode.bye, new byte[1]));
                    clientSocket.Shutdown(SocketShutdown.Both);
                    clientSocket.Disconnect(true);
                    return;
                }

                connectedClients.Add(remoteEndpoint);

                Logging.info(String.Format("Client connection accepted: {0} | #{1}/{2}", clientEndpoint.ToString(), connectedClients.Count + 1, CoreConfig.maximumServerMasterNodes));

                remoteEndpoint.start(clientSocket);
            }
        }
コード例 #2
0
ファイル: Network.cs プロジェクト: requin38/Ixian-Core
        /// <summary>
        ///  Attempts to connect to the given host name or IP address and transmit some data.
        ///  Note: This function has a possible delay of about 2 seconds.
        /// </summary>
        /// <param name="full_hostname">Hostname or IP address of the remote endpoint.</param>
        /// <returns>True, if the IP address is reachable.</returns>
        public static bool PingAddressReachable(String full_hostname)
        {
            // TODO TODO TODO TODO move this to another thread

            if (String.IsNullOrWhiteSpace(full_hostname))
            {
                return(false);
            }

            String[] hn_port = full_hostname.Split(':');
            if (hn_port.Length != 2)
            {
                return(false);
            }
            String hostname = hn_port[0];

            if (!IXICore.Utils.IxiUtils.validateIPv4(hostname))
            {
                return(false);
            }
            int port;

            if (int.TryParse(hn_port[1], out port) == false)
            {
                return(false);
            }
            if (port <= 0)
            {
                return(false);
            }

            TcpClient temp      = new TcpClient();
            bool      connected = false;

            try
            {
                Logging.info(String.Format("Testing client connectivity for {0}.", full_hostname));
                if (!temp.ConnectAsync(hostname, port).Wait(1000))
                {
                    return(false);
                }
                temp.Client.SendTimeout    = 500;
                temp.Client.ReceiveTimeout = 500;
                temp.Client.Blocking       = false;
                temp.Client.Send(new byte[1], 0, 0);
                connected = temp.Client.Connected;
                temp.Client.Send(CoreProtocolMessage.prepareProtocolMessage(ProtocolMessageCode.bye, new byte[1]));
                temp.Client.Shutdown(SocketShutdown.Both);
                temp.Close();
            }
            catch (SocketException) { connected = false; }
            return(connected);
        }
コード例 #3
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");
 }
コード例 #4
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;
            }
        }
コード例 #5
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))
                            {
                                byte[] challenge_response = null;
                                try
                                {
                                    // TODO TODO TODO TODO TODO try/catch wrapper will be removed when everybody upgrades
                                    int    challenge_len = reader.ReadInt32();
                                    byte[] challenge     = reader.ReadBytes(challenge_len);

                                    challenge_response = CryptoManager.lib.getSignature(challenge, Node.walletStorage.getPrimaryPrivateKey());
                                }
                                catch (Exception e)
                                {
                                }


                                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);
                                Node.setRequiredConsensus(consensus);

                                // Check for legacy level
                                ulong legacy_level = reader.ReadUInt64();

                                // Check for legacy node
                                if (Legacy.isLegacy(legacy_level))
                                {
                                    // TODO TODO TODO TODO check this out
                                    //endpoint.setLegacy(true);
                                }

                                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.syncPresenceList:
                {
                    byte[] pdata = PresenceList.getBytes();
                    byte[] ba    = CoreProtocolMessage.prepareProtocolMessage(ProtocolMessageCode.presenceList, pdata);
                    endpoint.sendData(ProtocolMessageCode.presenceList, pdata);
                }
                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);

                    // 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);
                            lock (PresenceList.presences)
                            {
                                // TODO re-verify this
                                Presence p = PresenceList.presences.Find(x => x.wallet.SequenceEqual(wallet));
                                if (p != null)
                                {
                                    byte[][] presence_chunks = p.getByteChunks();
                                    int      i = 0;
                                    foreach (byte[] presence_chunk in presence_chunks)
                                    {
                                        endpoint.sendData(ProtocolMessageCode.updatePresence, presence_chunk);
                                        i++;
                                    }
                                }
                                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().Length < 2)
                                        {
                                            Config.publicServerIP = 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 " + Config.serverPort + ".");
                                    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()));
            }
        }