diff options
Diffstat (limited to 'xbmc/network/ZeroconfBrowser.h')
-rw-r--r-- | xbmc/network/ZeroconfBrowser.h | 174 |
1 files changed, 174 insertions, 0 deletions
diff --git a/xbmc/network/ZeroconfBrowser.h b/xbmc/network/ZeroconfBrowser.h new file mode 100644 index 0000000..76a4439 --- /dev/null +++ b/xbmc/network/ZeroconfBrowser.h @@ -0,0 +1,174 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include <string> +#include <set> +#include <vector> +#include <map> + +#ifdef TARGET_WINDOWS +#undef SetPort // WIN32INCLUDES this is defined as SetPortA in WinSpool.h which is being included _somewhere_ +#endif + +//forwards +class CCriticalSection; + +/// this class provides support for zeroconf browsing +class CZeroconfBrowser +{ +public: + class ZeroconfService + { + public: + typedef std::map<std::string, std::string> tTxtRecordMap; + + ZeroconfService() = default; + ZeroconfService(const std::string& fcr_name, const std::string& fcr_type, const std::string& fcr_domain); + + /// easy conversion to string and back (used in czeronfdiretory to store this service) + ///@{ + static std::string toPath(const ZeroconfService& fcr_service); + static ZeroconfService fromPath(const std::string& fcr_path); //throws std::runtime_error on failure + ///@} + + /// general access methods + ///@{ + void SetName(const std::string& fcr_name); + const std::string& GetName() const {return m_name;} + + void SetType(const std::string& fcr_type); + const std::string& GetType() const {return m_type;} + + void SetDomain(const std::string& fcr_domain); + const std::string& GetDomain() const {return m_domain;} + ///@} + + /// access methods needed during resolve + ///@{ + void SetIP(const std::string& fcr_ip); + const std::string& GetIP() const {return m_ip;} + + void SetHostname(const std::string& fcr_hostname); + const std::string& GetHostname() const {return m_hostname;} + + void SetPort(int f_port); + int GetPort() const {return m_port;} + + void SetTxtRecords(const tTxtRecordMap& txt_records); + const tTxtRecordMap& GetTxtRecords() const { return m_txtrecords_map;} + ///@} + private: + //3 entries below identify a service + std::string m_name; + std::string m_type; + std::string m_domain; + + //2 entries below store 1 ip:port pair for this service + std::string m_ip; + int m_port = 0; + + //used for mdns in case dns resolution fails + //we store the hostname and resolve with mdns functions again + std::string m_hostname; + + //1 entry below stores the txt-record as a key value map for this service + tTxtRecordMap m_txtrecords_map; + }; + + // starts browsing + void Start(); + + // stops browsing + void Stop(); + + ///returns the list of found services + /// if this is updated, the following message with "zeroconf://" as path is sent: + /// CGUIMessage message(GUI_MSG_NOTIFY_ALL, 0, 0, GUI_MSG_UPDATE_PATH); + std::vector<ZeroconfService> GetFoundServices(); + ///@} + + // resolves a ZeroconfService to ip + port + // @param fcr_service the service to resolve + // @param f_timeout timeout in seconds for resolving + // the protocol part of CURL is the raw zeroconf service type + // added with AddServiceType (== needs further processing! e.g. _smb._tcp -> smb) + // @return true if it was successfully resolved (or scheduled), false if resolve + // failed (async or not) + bool ResolveService(ZeroconfService& fr_service, double f_timeout = 1.0); + + // class methods + // access to singleton; singleton gets created on call if not existent + // if zeroconf is disabled (!HAS_ZEROCONF), this will return a dummy implementation that + // just does nothings, otherwise the platform specific one + static CZeroconfBrowser* GetInstance(); + // release the singleton; (save to call multiple times) + static void ReleaseInstance(); + // returns false if ReleaseInstance() was called before + static bool IsInstantiated() { return smp_instance != 0; } + + virtual void ProcessResults() {} + + /// methods for browsing and getting results of it + ///@{ + /// adds a service type for browsing + /// @param fcr_service_type the service type as string, e.g. _smb._tcp. + /// @return false if it was already there + bool AddServiceType(const std::string& fcr_service_type); + + /// remove the specified service from discovery + /// @param fcr_service_type the service type as string, e.g. _smb._tcp. + /// @return if it was not found + bool RemoveServiceType(const std::string& fcr_service_type); + +protected: + //singleton: we don't want to get instantiated nor copied or deleted from outside + CZeroconfBrowser(); + CZeroconfBrowser(const CZeroconfBrowser&) = delete; + CZeroconfBrowser& operator=(const CZeroconfBrowser&) = delete; + virtual ~CZeroconfBrowser(); + + // pure virtual methods to implement for OS specific implementations + virtual bool doAddServiceType(const std::string& fcr_service_type) = 0; + virtual bool doRemoveServiceType(const std::string& fcr_service_type) = 0; + virtual std::vector<ZeroconfService> doGetFoundServices() = 0; + virtual bool doResolveService(ZeroconfService& fr_service, double f_timeout) = 0; + +private: + struct ServiceInfo + { + std::string type; + }; + + //protects data + CCriticalSection* mp_crit_sec; + typedef std::set<std::string> tServices; + tServices m_services; + bool m_started = false; + + static CZeroconfBrowser* smp_instance; +}; +#include <iostream> + +//debugging helper +inline std::ostream& operator<<(std::ostream& o, const CZeroconfBrowser::ZeroconfService& service){ + o << "(" << service.GetName() << "|" << service.GetType() << "|" << service.GetDomain() << ")"; + return o; +} + +//inline methods +inline bool operator<(CZeroconfBrowser::ZeroconfService const& fcr_lhs, CZeroconfBrowser::ZeroconfService const& fcr_rhs) +{ + return (fcr_lhs.GetName() + fcr_lhs.GetType() + fcr_lhs.GetDomain() < fcr_rhs.GetName() + fcr_rhs.GetType() + fcr_rhs.GetDomain()); +} + +inline bool operator==(CZeroconfBrowser::ZeroconfService const& fcr_lhs, CZeroconfBrowser::ZeroconfService const& fcr_rhs) +{ + return (fcr_lhs.GetName() == fcr_rhs.GetName() && fcr_lhs.GetType() == fcr_rhs.GetType() && fcr_lhs.GetDomain() == fcr_rhs.GetDomain() ); +} |