Пример #1
0
        void Receive_Notify(DhtClient client, LocationNotify notify)
        {
            if (notify.SignedLocation != null)
            {
                Store_Local(new DataReq(null, client.UserID, ServiceID, 0, notify.SignedLocation));
            }


            ClientInfo info;

            if (!Clients.SafeTryGetValue(client.RoutingID, out info))
            {
                return;
            }

            if (notify.GoingOffline)
            {
                Clients.SafeRemove(client.RoutingID);
                SignalUpdate(info, false);
                return;
            }

            info.LastSeen    = Core.TimeNow;
            info.PingTimeout = notify.Timeout;
            info.NextPing    = Core.TimeNow.AddSeconds(notify.Timeout);
        }
Пример #2
0
        private void GoingOffline()
        {
            foreach (DhtClient client in NotifyUsers.Keys)
            {
                LocationNotify notify = new LocationNotify();
                notify.Timeout      = CurrentTimeout;
                notify.GoingOffline = true;
                Network.LightComm.SendReliable(client, ServiceID, 0, notify, true);
            }

            NotifyUsers.Clear();
        }
Пример #3
0
        void Receive_Ping(DhtClient client, LocationPing ping)
        {
            if (Core.User.Settings.Invisible)
            {
                return;
            }

            LocationNotify notify = new LocationNotify();

            RecentPings.AddFirst(Core.TimeNow);
            while (RecentPings.Count > 30)
            {
                RecentPings.RemoveLast();
            }

            // we want a target of 20 pings per minute ( 1 every 3 seconds)
            // pings per minute = RecentPings.count / (Core.TimeNow - RecentPings.Last).ToMinutes()
            float pingsPerMinute = (float)RecentPings.Count / (float)(Core.TimeNow - RecentPings.Last.Value).Minutes;

            notify.Timeout = (int)(60.0 * pingsPerMinute / 20.0); // 20 is target rate, so if we have 40ppm, multiplier is 2, timeout 120seconds
            notify.Timeout = Math.Max(60, notify.Timeout);        // use 60 as lowest timeout
            CurrentTimeout = notify.Timeout;

            if (ping.RemoteVersion < LocalClient.Data.Version)
            {
                notify.SignedLocation = LocalClient.SignedData;
            }

            if (PendingNotifications.Contains(client))
            {
                PendingNotifications.Remove(client);
            }

            //put node on interested list
            NotifyUsers[client] = Core.TimeNow.AddSeconds(notify.Timeout + 15);


            // *** small security concern, notifies are not signed so they could be forged
            // signing vs unsigning is 144 vs 7 bytes, the bandwidth benefits outweigh forging
            // someone's online status at the moment
            // byte[] unsigned = notify.Encode(Network.Protocol);
            // byte[] signed = SignedData.Encode(Network.Protocol, Core.User.Settings.KeyPair, notify);


            Network.LightComm.SendReliable(client, ServiceID, 0, notify);
        }
Пример #4
0
        void LightComm_ReceiveData(DhtClient client, byte[] data)
        {
            G2Header root = new G2Header(data);

            if (G2Protocol.ReadPacket(root))
            {
                if (root.Name == LocationPacket.Ping)
                {
                    Receive_Ping(client, LocationPing.Decode(root));
                }

                if (root.Name == LocationPacket.Notify)
                {
                    Receive_Notify(client, LocationNotify.Decode(root));
                }
            }
        }
Пример #5
0
        public static LocationNotify Decode(G2Header root)
        {
            LocationNotify notify = new LocationNotify();

            if (G2Protocol.ReadPayload(root))
            {
                notify.SignedLocation = Utilities.ExtractBytes(root.Data, root.PayloadPos, root.PayloadSize);
            }

            G2Protocol.ResetPacket(root);

            G2Header child = new G2Header(root.Data);

            while (G2Protocol.ReadNextChild(root, child) == G2ReadResult.PACKET_GOOD)
            {
                if (child.Name == Packet_GoingOffline)
                {
                    notify.GoingOffline = true;
                    continue;
                }

                if (!G2Protocol.ReadPayload(child))
                {
                    continue;
                }

                switch (child.Name)
                {
                case Packet_Timeout:
                    notify.Timeout = CompactNum.ToInt32(child.Data, child.PayloadPos, child.PayloadSize);
                    break;
                }
            }

            return(notify);
        }
Пример #6
0
        public static LocationNotify Decode(G2Header root)
        {
            LocationNotify notify = new LocationNotify();

            if (G2Protocol.ReadPayload(root))
                notify.SignedLocation = Utilities.ExtractBytes(root.Data, root.PayloadPos, root.PayloadSize);

            G2Protocol.ResetPacket(root);

            G2Header child = new G2Header(root.Data);

            while (G2Protocol.ReadNextChild(root, child) == G2ReadResult.PACKET_GOOD)
            {
                if (child.Name == Packet_GoingOffline)
                {
                    notify.GoingOffline = true;
                    continue;
                }

                if (!G2Protocol.ReadPayload(child))
                    continue;

                switch (child.Name)
                {
                    case Packet_Timeout:
                        notify.Timeout = CompactNum.ToInt32(child.Data, child.PayloadPos, child.PayloadSize);
                        break;
                }
            }

            return notify;
        }
Пример #7
0
        void Core_SecondTimer()
        {
            OpCore global = Core.Context.Lookup;

            // global publish - so others can find entry to the op
            if (Core.User.Settings.OpAccess != AccessType.Secret &&
                global != null &&
                global.Network.Responsive &&
                (global.Firewall == FirewallType.Open || Network.UseLookupProxies) &&
                Core.TimeNow > NextGlobalPublish)
            {
                PublishGlobal();
            }


            if (!Network.Established)
            {
                return;
            }


            // run code below every quarter second
            if (Core.TimeNow.Second % 15 != 0)
            {
                return;
            }


            // keep local client from being pinged, or removed
            LocalClient.LastSeen = Core.TimeNow.AddMinutes(1);
            LocalClient.NextPing = Core.TimeNow.AddMinutes(1);


            // remove expired clients - either from not notifying us, or we've lost interest and stopped pinging
            Clients.LockWriting(delegate()
            {
                foreach (ClientInfo client in Clients.Values.Where(c => Core.TimeNow > c.Timeout).ToArray())
                {
                    Clients.Remove(client.RoutingID);
                    SignalUpdate(client, false);
                }
            });


            // get form services users that we should keep tabs on
            LocalPings.Clear();
            KnowOnline.Invoke(LocalPings);


            // ping clients that we are locally caching, or we have interest in
            Clients.LockReading(delegate()
            {
                foreach (ClientInfo client in (from c in Clients.Values
                                               where Core.TimeNow > c.NextPing &&
                                               (Network.Routing.InCacheArea(c.UserID) || LocalPings.Contains(c.UserID))
                                               select c).ToArray())
                {
                    Send_Ping(client);
                }
            });


            // remove users no longer interested in our upates
            foreach (DhtClient expired in (from id in NotifyUsers.Keys
                                           where Core.TimeNow > NotifyUsers[id]
                                           select id).ToArray())
            {
                NotifyUsers.Remove(expired);

                if (PendingNotifications.Contains(expired))
                {
                    PendingNotifications.Remove(expired);
                }
            }


            // send 2 per second, if new update, start over again
            foreach (DhtClient client in PendingNotifications.Take(2).ToArray())
            {
                LocationNotify notify = new LocationNotify();
                notify.Timeout        = CurrentTimeout;
                notify.SignedLocation = LocalClient.SignedData;
                Network.LightComm.SendReliable(client, ServiceID, 0, notify);

                PendingNotifications.Remove(client);
            }
        }