protected virtual void CheckKeepalive(IPAddress ip, ServiceEntry svc)
        {
            if (KeepalivePing)
            {
                Ping ping   = new Ping();
                var  result = ping.Send(ip, (int)KeepaliveTimeout * 1000);

                if (result.Status != IPStatus.Success)
                {
                    Debug.WriteLine("Removed service {0} at {1} due to keepalive ping failure", svc.Service, svc.Host);
                    RemoveService(svc);
                    return;
                }
            }

            if (KeepaliveTcp)
            {
                using (var sock = new KeepaliveSocket(ip, svc.Port))
                {
                    bool tcpConnected = sock.CanConnect((int)KeepaliveTimeout * 1000);
                    if (!tcpConnected)
                    {
                        Debug.WriteLine("Removed service {0} at {1}:{2} due to Tcp Connect failure", svc.Service, svc.Host, svc.Port);
                        RemoveService(svc);
                        return;
                    }
                }
            }

            // Service is alive
            svc.LastSeenAlive = DateTime.Now;
            HostUpdated?.Invoke(this, svc);
        }
        public virtual void Init()
        {
            if (_disposedValue)
            {
                throw new ObjectDisposedException("ServiceDirectory");
            }

            _mdns.NetworkInterfaceDiscovered += (s, e) =>
            {
                // Ask for the name of all services.
                _sd.QueryAllServices();
            };

            _sd.ServiceDiscovered += (s, serviceName) =>
            {
                // Check if this is a service we're interested in
                bool interesting = true;
                if (FilterFunction != null)
                {
                    interesting = FilterFunction(serviceName.ToString());
                }
                if (!interesting)
                {
                    return;
                }

                // Ask for the name of instances of the service.
                _mdns.SendQuery(serviceName, type: DnsType.PTR);
            };

            _sd.ServiceInstanceDiscovered += (s, e) =>
            {
                // Ask for the service instance details.
                _mdns.SendQuery(e.ServiceInstanceName, type: DnsType.SRV);
            };

            _sd.ServiceInstanceShutdown += (s, e) =>
            {
                Debug.WriteLine("Removing service instance {0} from MDNS message", e.ServiceInstanceName);
                RemoveServiceByName(e.ServiceInstanceName.ToString());
            };

            _mdns.AnswerReceived += (s, e) =>
            {
                // Is this an answer to a service instance details?
                var servers = e.Message.Answers.OfType <SRVRecord>();
                foreach (var server in servers)
                {
                    // For some reason, some services slip through the cracks of the first filter at ServiceDiscovered
                    // and we have to filter again.
                    bool interesting = true;
                    if (FilterFunction != null)
                    {
                        interesting = FilterFunction(server.Name.ToString());
                    }
                    if (!interesting)
                    {
                        continue;
                    }


                    var newSvc = new ServiceEntry
                    {
                        Host    = server.Target.ToString(),
                        Port    = server.Port,
                        Service = server.Name.ToString()
                    };

                    AddService(newSvc);

                    // Query IP addresses (only IPv4)
                    _mdns.SendQuery(server.Target, type: DnsType.A);
                }

                // Is this an answer to host addresses?
                var addresses = e.Message.Answers.OfType <AddressRecord>();
                foreach (var address in addresses)
                {
                    // Find corresponding host
                    lock (_entries)
                    {
                        var host = from entry in _entries where entry.Host == address.Name select entry;
                        foreach (var h in host)
                        {
                            if (!h.IPAddresses.Contains(address.Address))
                            {
                                h.IPAddresses.Add(address.Address);
                            }
                            HostUpdated?.Invoke(this, h);
                        }
                    }
                }
            };

            _mdns.Start();

            ScheduleKeepAliveCheck();
        }