Esempio n. 1
0
        // Generate an initial presence list
        public static void generatePresenceList(string initial_ip, char type = 'M')
        {
            Logging.info("Generating presence list.");

            // Initialize with the default presence state
            curNodePresenceAddress = new PresenceAddress(Config.device_id, string.Format("{0}:{1}", initial_ip, Config.serverPort), type, Config.version, 0, null);
            curNodePresence        = new Presence(Node.walletStorage.getPrimaryAddress(), Node.walletStorage.getPrimaryPublicKey(), null, curNodePresenceAddress);
        }
Esempio n. 2
0
 public Presence(byte[] wallet_address, byte[] node_pubkey, byte[] node_meta, PresenceAddress node_address)
 {
     version   = 0;
     wallet    = wallet_address;
     pubkey    = node_pubkey;
     metadata  = node_meta;
     addresses = new List <PresenceAddress> {
     };
     addresses.Add(node_address);
     owner = " ";
 }
Esempio n. 3
0
        public Presence(byte[] wallet_address, byte[] node_pubkey, string node_ip, char node_type, string node_version)
        {
            version   = 0;
            wallet    = wallet_address;
            pubkey    = node_pubkey;
            metadata  = null;
            addresses = new List <PresenceAddress> {
            };

            // Generate a device id
            string          deviceId = Guid.NewGuid().ToString();
            PresenceAddress address  = new PresenceAddress(deviceId, node_ip, node_type, node_version, 0, null);

            addresses.Add(address);
            owner = " ";
        }
Esempio n. 4
0
        public void start(Socket socket = null)
        {
            if (fullyStopped)
            {
                Logging.error("Can't start a fully stopped RemoteEndpoint");
                return;
            }

            if (running)
            {
                return;
            }

            if (socket != null)
            {
                clientSocket = socket;
            }
            if (clientSocket == null)
            {
                Logging.error("Could not start NetworkRemoteEndpoint, socket is null");
                return;
            }

            prepareSocket(clientSocket);

            remoteIP        = (IPEndPoint)clientSocket.RemoteEndPoint;
            address         = remoteIP.Address.ToString();
            fullAddress     = address + ":" + remoteIP.Port;
            presence        = null;
            presenceAddress = null;

            lock (subscribedAddresses)
            {
                subscribedAddresses.Clear();
            }

            lastDataReceivedTime = Clock.getTimestamp();
            lastDataSentTime     = Clock.getTimestamp();

            state = RemoteEndpointState.Established;

            timeDifference   = 0;
            timeSyncComplete = false;
            timeSyncs.Clear();

            running = true;

            // Abort all related threads
            if (recvThread != null)
            {
                recvThread.Abort();
                recvThread = null;
            }
            if (sendThread != null)
            {
                sendThread.Abort();
                sendThread = null;
            }
            if (parseThread != null)
            {
                parseThread.Abort();
                parseThread = null;
            }

            try
            {
                TLC = new ThreadLiveCheck();
                // Start receive thread
                recvThread      = new Thread(new ThreadStart(recvLoop));
                recvThread.Name = "Network_Remote_Endpoint_Receive_Thread";
                recvThread.Start();

                // Start send thread
                sendThread      = new Thread(new ThreadStart(sendLoop));
                sendThread.Name = "Network_Remote_Endpoint_Send_Thread";
                sendThread.Start();

                // Start parse thread
                parseThread      = new Thread(new ThreadStart(parseLoop));
                parseThread.Name = "Network_Remote_Endpoint_Parse_Thread";
                parseThread.Start();
            }
            catch (Exception e)
            {
                Logging.error("Exception start remote endpoint: {0}", e.Message);
            }
        }
Esempio n. 5
0
        // Update a presence entry. If the wallet address is not found, it creates a new entry in the Presence List.
        // If the wallet address is found in the presence list, it adds any new addresses from the specified presence.
        public static Presence updateEntry(Presence presence, RemoteEndpoint skipEndpoint = null)
        {
            if (presence == null)
            {
                return(null);
            }

            bool entryUpdated = false;

            Presence return_presence = null;

            lock (presences)
            {
                Presence pr = presences.Find(x => x.wallet.SequenceEqual(presence.wallet));
                if (pr != null)
                {
                    entryUpdated = false;

                    // Go through all addresses and add any missing ones
                    foreach (PresenceAddress local_addr in presence.addresses)
                    {
                        long currentTime = Core.getCurrentTimestamp();
                        long lTimestamp  = local_addr.lastSeenTime;
                        // Check for tampering. Includes a +300, -30 second synchronization zone
                        if ((currentTime - lTimestamp) > 300 || (currentTime - lTimestamp) < -30)
                        {
                            Logging.warn(string.Format("[PL] Potential KEEPALIVE tampering for {0} {1}. Skipping; {2} - {3}", Crypto.hashToString(pr.wallet), local_addr.address, currentTime, lTimestamp));
                            continue;
                        }

                        bool addressfound = false;

                        PresenceAddress addr = pr.addresses.Find(x => x.device == local_addr.device);
                        if (addr != null)
                        {
                            addressfound = true;
                            if (addr.address != local_addr.address)
                            {
                                addr.address      = local_addr.address;
                                addr.lastSeenTime = local_addr.lastSeenTime;
                                entryUpdated      = true;
                            }
                            else if (addr.lastSeenTime < local_addr.lastSeenTime)
                            {
                                addr.lastSeenTime = local_addr.lastSeenTime;
                                entryUpdated      = true;
                                //Console.WriteLine("[PL] Last time updated for {0}", addr.device);
                            }
                        }

                        // Add the address if it's not found
                        if (addressfound == false && entryUpdated == false)
                        {
                            //Logging.info("[PL] Adding new address for {0}", presence.wallet);
                            pr.addresses.Add(local_addr);
                            entryUpdated = true;

                            lock (presenceCount)
                            {
                                if (!presenceCount.ContainsKey(local_addr.type))
                                {
                                    presenceCount.Add(local_addr.type, 0);
                                }
                                presenceCount[local_addr.type]++;
                            }
                        }
                    }

                    // Check if the entry was updated
                    if (entryUpdated == false)
                    {
                        return(pr);
                    }

                    // Return the stored presence list entity
                    return_presence = pr;
                }
                else
                {
                    // Insert a new entry
                    //Console.WriteLine("[PL] Adding new entry for {0}", presence.wallet);
                    presences.Add(presence);

                    lock (presenceCount)
                    {
                        foreach (PresenceAddress pa in presence.addresses)
                        {
                            if (!presenceCount.ContainsKey(pa.type))
                            {
                                presenceCount.Add(pa.type, 0);
                            }
                            presenceCount[pa.type]++;
                        }
                    }

                    return_presence = presence;
                }
            }

            return(return_presence);
        }
Esempio n. 6
0
        // Called when receiving a keepalive network message. The PresenceList will update the appropriate entry based on the timestamp.
        // Returns TRUE if it updated an entry in the PL
        // Sets the out address parameter to be the KA wallet's address or null if an error occured
        public static bool receiveKeepAlive(byte[] bytes, out byte[] address)
        {
            address = null;

            // Get the current timestamp
            long currentTime = Core.getCurrentTimestamp();

            try
            {
                using (MemoryStream m = new MemoryStream(bytes))
                {
                    using (BinaryReader reader = new BinaryReader(m))
                    {
                        int    keepAliveVersion = reader.ReadInt32();
                        int    walletLen        = reader.ReadInt32();
                        byte[] wallet           = reader.ReadBytes(walletLen);

                        // Assign the out address parameter
                        address = wallet;

                        string deviceid  = reader.ReadString();
                        long   timestamp = reader.ReadInt64();
                        string hostname  = reader.ReadString();
                        char   node_type = '0';
                        if (keepAliveVersion > 0)
                        {
                            node_type = reader.ReadChar();
                        }
                        int    sigLen    = reader.ReadInt32();
                        byte[] signature = reader.ReadBytes(sigLen);
                        //Logging.info(String.Format("[PL] KEEPALIVE request from {0}", hostname));

                        if (node_type == 'C' || node_type == 'R')
                        {
                            // all good, continue
                        }
                        else if (node_type == 'M' || node_type == 'H')
                        {
                            // check balance
                            if (Node.walletState.getWalletBalance(wallet) < CoreConfig.minimumMasterNodeFunds)
                            {
                                return(false);
                            }
                        }
                        else if (node_type != '0')
                        {
                            // reject everything else
                            return(false);
                        }

                        lock (presences)
                        {
                            Presence listEntry = presences.Find(x => x.wallet.SequenceEqual(wallet));
                            if (listEntry == null && wallet.SequenceEqual(Node.walletStorage.getPrimaryAddress()))
                            {
                                Logging.error(string.Format("My entry was removed from local PL, readding."));
                                updateEntry(curNodePresence);
                                listEntry = presences.Find(x => x.wallet.SequenceEqual(wallet));
                            }

                            // Check if no such wallet found in presence list
                            if (listEntry == null)
                            {
                                // request for additional data
                                using (MemoryStream mw = new MemoryStream())
                                {
                                    using (BinaryWriter writer = new BinaryWriter(mw))
                                    {
                                        writer.Write(wallet.Length);
                                        writer.Write(wallet);

                                        CoreProtocolMessage.broadcastProtocolMessage(new char[] { 'M', 'R' }, ProtocolMessageCode.getPresence, mw.ToArray(), null);
                                    }
                                }
                                return(false);
                            }
                            if (keepAliveVersion == 0)
                            {
                                // Verify the signature
                                if (CryptoManager.lib.verifySignature(Encoding.UTF8.GetBytes(CoreConfig.ixianChecksumLockString + "-" + deviceid + "-" + timestamp + "-" + hostname), listEntry.pubkey, signature) == false)
                                {
                                    Logging.warn(string.Format("[PL] KEEPALIVE tampering for {0} {1}, incorrect Sig.", Base58Check.Base58CheckEncoding.EncodePlain(listEntry.wallet), hostname));
                                    return(false);
                                }
                            }
                            else
                            {
                                // Verify the signature
                                if (CryptoManager.lib.verifySignature(bytes.Take(bytes.Length - sigLen - 4).ToArray(), listEntry.pubkey, signature) == false)
                                {
                                    Logging.warn(string.Format("[PL] KEEPALIVE tampering for {0} {1}, incorrect Sig.", Base58Check.Base58CheckEncoding.EncodePlain(listEntry.wallet), hostname));
                                    return(false);
                                }
                            }

                            PresenceAddress pa = listEntry.addresses.Find(x => x.address == hostname && x.device == deviceid);

                            if (pa != null)
                            {
                                // Check the node type
                                if (pa.lastSeenTime != timestamp)
                                {
                                    // Check for outdated timestamp
                                    if (timestamp < pa.lastSeenTime)
                                    {
                                        // We already have a newer timestamp for this entry
                                        return(false);
                                    }

                                    // Check for tampering. Includes a +300, -30 second synchronization zone
                                    if ((currentTime - timestamp) > 300 || (currentTime - timestamp) < -30)
                                    {
                                        Logging.warn(string.Format("[PL] Potential KEEPALIVE tampering for {0} {1}. Timestamp {2}", Base58Check.Base58CheckEncoding.EncodePlain(listEntry.wallet), pa.address, timestamp));
                                        return(false);
                                    }

                                    // Update the timestamp
                                    pa.lastSeenTime = timestamp;
                                    pa.signature    = signature;
                                    if (node_type != '0')
                                    {
                                        if (pa.type != node_type)
                                        {
                                            lock (presenceCount)
                                            {
                                                presenceCount[pa.type]--;
                                                if (!presenceCount.ContainsKey(node_type))
                                                {
                                                    presenceCount.Add(node_type, 0);
                                                }
                                                presenceCount[node_type]++;
                                            }
                                        }
                                        pa.type = node_type;
                                    }

                                    if (pa.type == 'M' || pa.type == 'H')
                                    {
                                        PeerStorage.addPeerToPeerList(hostname, wallet);
                                    }

                                    //Console.WriteLine("[PL] LASTSEEN for {0} - {1} set to {2}", hostname, deviceid, pa.lastSeenTime);
                                    return(true);
                                }
                            }
                            else
                            {
                                if (wallet.SequenceEqual(Node.walletStorage.getPrimaryAddress()))
                                {
                                    updateEntry(curNodePresence);
                                    return(true);
                                }
                                else
                                {
                                    using (MemoryStream mw = new MemoryStream())
                                    {
                                        using (BinaryWriter writer = new BinaryWriter(mw))
                                        {
                                            writer.Write(wallet.Length);
                                            writer.Write(wallet);

                                            CoreProtocolMessage.broadcastProtocolMessage(new char[] { 'M', 'R' }, ProtocolMessageCode.getPresence, mw.ToArray(), null);
                                        }
                                    }
                                    return(false);
                                }
                            }
                        }
                    }
                }
            }
            catch (Exception e)
            {
                Logging.error("Exception occured in receiveKeepAlive: " + e);
                return(false);
            }

            return(false);
        }
Esempio n. 7
0
        public static bool removeAddressEntry(byte[] wallet_address, PresenceAddress address)
        {
            lock (presences)
            {
                //Console.WriteLine("[PL] Received removal for {0} : {1}", wallet_address, address.address);
                Presence listEntry = presences.Find(x => x.wallet.SequenceEqual(wallet_address));

                // Check if there is such an entry in the presence list
                if (listEntry != null)
                {
                    var addresses_to_remove = listEntry.addresses.FindAll(x => x == address);

                    foreach (var addr in addresses_to_remove)
                    {
                        lock (presenceCount)
                        {
                            if (presenceCount.ContainsKey(addr.type))
                            {
                                presenceCount[addr.type]--;
                            }
                        }
                        listEntry.addresses.Remove(addr);
                    }

                    int address_count = listEntry.addresses.Count;
                    //Console.WriteLine("[PL] --->> Addresses: {0}", address_count);

                    if (address_count == 0)
                    {
                        // Remove it from the list
                        presences.Remove(listEntry);
                    }

                    // If presence address is a relay node, remove all other presences with matching ip:port
                    // TODO: find a better way to handle this while preventing modify-during-enumeration issues
                    if (address.type == 'R')
                    {
                        // Retrieve the ip+port of the relay address
                        string relay_address = address.address;

                        // Store a copy of the presence list to allow safe modifications while enumerating
                        List <Presence> safe_presences = new List <Presence>(presences);

                        // Go through the entire presence list
                        foreach (Presence pr in safe_presences)
                        {
                            // Store a list of presence addresses that correspond to the relay node we're removing
                            List <PresenceAddress> relayClients = new List <PresenceAddress>();

                            foreach (PresenceAddress pa in pr.addresses)
                            {
                                if (pa.address.SequenceEqual(relay_address))
                                {
                                    // Check if it's a client node
                                    if (pa.type == 'C')
                                    {
                                        relayClients.Add(pa);
                                    }
                                }
                            }

                            // Check if the presence contains at least one relay client
                            if (relayClients.Count > 0)
                            {
                                // Go through each relay client and safely remove it's address entry
                                // Note that it also propagates network messages
                                foreach (PresenceAddress par in relayClients)
                                {
                                    removeAddressEntry(pr.wallet, par);
                                }

                                relayClients.Clear();
                            }
                        }

                        // Clear the safe list of presences
                        safe_presences.Clear();
                    }

                    return(true);
                }
            }

            return(false);
        }