// Copyright 2014 The Chromium OS Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef PEERD_AVAHI_SERVICE_DISCOVERER_H_ #define PEERD_AVAHI_SERVICE_DISCOVERER_H_ #include #include #include #include #include #include #include #include #include "peerd/service.h" #include "peerd/typedefs.h" namespace dbus { class ObjectProxy; class Signal; } // namespace dbus namespace peerd { class PeerManagerInterface; // Avahi allows consumers to discover services in two phases: browsing and // resolution. Service discovery is done by requesting Avahi to create // AvahiServiceBrowser objects for a particular service type (e.g. // "_privet._tcp"). Inside our own process, we need to keep DBus proxies // for those objects around. // // Then, we start getting signals for service creation/deletion from Avahi // through our AvahiServiceBrowser objects. Avahi identifies services by a // combination of: // 1) The interface we've discovered that service on // 2) The unique name of the service // 3) The type of the service // 4) The domain the service was discovered on. // // For each instance of a service, we then need to ask Avahi to create an // AvahiServiceResolver to read the TXT record and signal changes to the TXT // record. Again, we need to keep local DBus proxies for those remote // objects. // // When we get a signal that a service instance is gone, we remove the // resolver from Avahi. When we have no peers advertising a particular // service type via root _serbus records, we remove the service browser for // that type. class AvahiServiceDiscoverer final { public: AvahiServiceDiscoverer(const scoped_refptr& bus, dbus::ObjectProxy* avahi_proxy, PeerManagerInterface* peer_manager_); ~AvahiServiceDiscoverer(); void RegisterAsync(const CompletionAction& completion_callback); private: using avahi_if_t = int32_t; using avahi_proto_t = int32_t; // Either IPv4 or IPv6. using TxtList = std::vector>; // DBus type aay. // A resolver corrresponds to a particular name/type/domain/interface tuple, // but we organize them by type for book keeping reasons, and so this is just // a tuple. using resolv_key_t = std::tuple; using ResolversForType = std::map; // A map of service types to the resolvers for that type. using ResolverMap = std::map; static bool txt_list2service_info(const TxtList& txt_list, Service::ServiceInfo* info); // Creates a new AvahiServiceBrowser, hooks up signals, returns it. // |cb| is called asynchronously with the success or failure of // signal registration. dbus::ObjectProxy* BrowseServices(const std::string& service_type, const CompletionAction& cb); // Updates internal datastructures to reflect that the root serbus // service for a peer has changed. This may cause us to stop browsing // for one or more service types if no other peers claim to support // those service types. void OnPeerServicesChanged(const std::string& peer_id, std::set new_service_types); void OnPeerServicesRemoved(const std::string& peer_id); // Listen to changes in TXT records for a service. void RegisterResolver(avahi_if_t interface, const std::string& name, const std::string& type, const std::string& domain); // Stop listening to TXT record changes. void RemoveResolver(avahi_if_t interface, const std::string& name, const std::string& type, const std::string& domain); // Logic to respond to new services being discovered/removed. void HandleItemNew(avahi_if_t interface, avahi_proto_t protocol, const std::string& name, const std::string& type, const std::string& domain, uint32_t flags); void HandleItemRemove(avahi_if_t interface, avahi_proto_t protocol, const std::string& name, const std::string& type, const std::string& domain, uint32_t flags); // Signals that Avahi has had some serious trouble. void HandleFailure(const std::string& service_type, const std::string& message); // For notifications from our AvahiServiceResolver(s). void HandleFound(dbus::Signal* signal); // And in case we encounter failure in a Resolver... void HandleResolverFailure(avahi_if_t interface, const std::string& name, const std::string& type, const std::string& domain, dbus::Signal* signal); scoped_refptr bus_; dbus::ObjectProxy* avahi_proxy_; PeerManagerInterface* peer_manager_; avahi_proto_t protocol_; // We support one protocol per discoverer (IPv4). dbus::ObjectProxy* serbus_browser_; // A map from service type to the browser for that service type. std::map browsers_; // A map from root serbus record names to the corresponding unique peer id. std::map serbus_record_to_peer_id_; // A map from service type to list of peer ids of peers advertising that // service. std::map> peers_for_service_; ResolverMap resolvers_; // Should be last member to invalidate weak pointers in child objects // and avoid callbacks while partially destroyed. base::WeakPtrFactory weak_ptr_factory_{this}; DISALLOW_COPY_AND_ASSIGN(AvahiServiceDiscoverer); }; } // namespace peerd #endif // PEERD_AVAHI_SERVICE_DISCOVERER_H_