1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
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() );
}
|