2 * Copyright (C) 2017 Christian Browet
3 * This file is part of Kodi - https://kodi.tv
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 * See LICENSES/README.md for more information.
9 #include "ZeroconfBrowserAndroid.h"
11 #include "GUIUserMessages.h"
12 #include "ServiceBroker.h"
13 #include "guilib/GUIComponent.h"
14 #include "guilib/GUIMessage.h"
15 #include "guilib/GUIWindowManager.h"
16 #include "network/DNSNameCache.h"
17 #include "utils/log.h"
21 #include <androidjni/Context.h>
22 #include <androidjni/jutils-details.hpp>
24 CZeroconfBrowserAndroid::CZeroconfBrowserAndroid()
25 : m_manager(CJNIContext::getSystemService(CJNIContext::NSD_SERVICE
))
29 CZeroconfBrowserAndroid::~CZeroconfBrowserAndroid()
31 std::unique_lock
<CCriticalSection
> lock(m_data_guard
);
32 //make sure there are no browsers anymore
33 for (const auto& it
: m_service_browsers
)
34 doRemoveServiceType(it
.first
);
37 bool CZeroconfBrowserAndroid::doAddServiceType(const std::string
& fcr_service_type
)
39 CZeroconfBrowserAndroidDiscover
* discover
= new CZeroconfBrowserAndroidDiscover(this);
41 // Remove trailing dot
42 // std::string nsdType = fcr_service_type;
43 // if (nsdType.compare(nsdType.size() - 1, 1, ".") == 0)
44 // nsdType = nsdType.substr(0, nsdType.size() - 1);
46 CLog::Log(LOGDEBUG
, "CZeroconfBrowserAndroid::doAddServiceType: {}", fcr_service_type
);
47 m_manager
.discoverServices(fcr_service_type
, 1 /* PROTOCOL_DNS_SD */, *discover
);
51 std::unique_lock
<CCriticalSection
> lock(m_data_guard
);
52 m_service_browsers
.insert(std::make_pair(fcr_service_type
, discover
));
57 bool CZeroconfBrowserAndroid::doRemoveServiceType(const std::string
& fcr_service_type
)
59 CLog::Log(LOGDEBUG
, "CZeroconfBrowserAndroid::doRemoveServiceType: {}", fcr_service_type
);
61 CZeroconfBrowserAndroidDiscover
* discover
;
62 //search for this browser and remove it from the map
64 std::unique_lock
<CCriticalSection
> lock(m_data_guard
);
65 tBrowserMap::iterator it
= m_service_browsers
.find(fcr_service_type
);
66 if(it
== m_service_browsers
.end())
70 discover
= it
->second
;
71 if (discover
->IsActive())
72 m_manager
.stopServiceDiscovery(*discover
);
73 // Be extra careful: Discover listener is gone as of now
74 m_service_browsers
.erase(it
);
77 //remove the services of this browser
79 std::unique_lock
<CCriticalSection
> lock(m_data_guard
);
80 tDiscoveredServicesMap::iterator it
= m_discovered_services
.find(discover
);
81 if(it
!= m_discovered_services
.end())
82 m_discovered_services
.erase(it
);
89 std::vector
<CZeroconfBrowser::ZeroconfService
> CZeroconfBrowserAndroid::doGetFoundServices()
91 std::vector
<CZeroconfBrowser::ZeroconfService
> ret
;
92 std::unique_lock
<CCriticalSection
> lock(m_data_guard
);
93 for (const auto& it
: m_discovered_services
)
95 const auto& services
= it
.second
;
96 for (const auto& service
: services
)
98 ret
.push_back(service
.first
);
104 bool CZeroconfBrowserAndroid::doResolveService(CZeroconfBrowser::ZeroconfService
& fr_service
, double f_timeout
)
106 jni::CJNINsdServiceInfo service
;
107 service
.setServiceName(fr_service
.GetName());
108 service
.setServiceType(fr_service
.GetType());
110 CZeroconfBrowserAndroidResolve resolver
;
111 m_manager
.resolveService(service
, resolver
);
113 if (!resolver
.m_resolutionDone
.Wait(std::chrono::duration
<double, std::milli
>(f_timeout
* 1000)))
115 CLog::Log(LOGERROR
, "ZeroconfBrowserAndroid: DNSServiceResolve Timeout error");
119 if (resolver
.m_errorCode
!= -1)
121 CLog::Log(LOGERROR
, "ZeroconfBrowserAndroid: DNSServiceResolve returned (error = {})",
122 resolver
.m_errorCode
);
126 fr_service
.SetHostname(resolver
.m_retServiceInfo
.getHost().getHostName());
127 fr_service
.SetIP(resolver
.m_retServiceInfo
.getHost().getHostAddress());
128 fr_service
.SetPort(resolver
.m_retServiceInfo
.getPort());
130 CZeroconfBrowser::ZeroconfService::tTxtRecordMap recordMap
;
131 jni::CJNISet
<jni::jhstring
> txtKey
= resolver
.m_retServiceInfo
.getAttributes().keySet();
132 jni::CJNIIterator
<jni::jhstring
> it
= txtKey
.iterator();
135 jni::jhstring k
= it
.next();
136 jni::jhbyteArray v
= resolver
.m_retServiceInfo
.getAttributes().get(k
);
138 std::string key
= jni::jcast
<std::string
>(k
);
139 std::vector
<char> vv
= jni::jcast
<std::vector
<char>>(v
);
140 std::string value
= std::string(vv
.begin(), vv
.end());
142 CLog::Log(LOGDEBUG
, "ZeroconfBrowserAndroid: TXT record {} = {} ({})", key
, value
, vv
.size());
144 recordMap
.insert(std::make_pair(key
, value
));
146 fr_service
.SetTxtRecords(recordMap
);
147 return (!fr_service
.GetIP().empty());
150 /// adds the service to list of found services
151 void CZeroconfBrowserAndroid::addDiscoveredService(CZeroconfBrowserAndroidDiscover
* browser
, CZeroconfBrowser::ZeroconfService
const& fcr_service
)
153 std::unique_lock
<CCriticalSection
> lock(m_data_guard
);
154 tDiscoveredServicesMap::iterator browserIt
= m_discovered_services
.find(browser
);
155 if(browserIt
== m_discovered_services
.end())
157 //first service by this browser
158 browserIt
= m_discovered_services
.insert(make_pair(browser
, std::vector
<std::pair
<ZeroconfService
, unsigned int> >())).first
;
160 //search this service
161 std::vector
<std::pair
<ZeroconfService
, unsigned int> >& services
= browserIt
->second
;
162 std::vector
<std::pair
<ZeroconfService
, unsigned int> >::iterator serviceIt
= services
.begin();
163 for( ; serviceIt
!= services
.end(); ++serviceIt
)
165 if(serviceIt
->first
== fcr_service
)
168 if(serviceIt
== services
.end())
169 services
.emplace_back(fcr_service
, 1);
174 void CZeroconfBrowserAndroid::removeDiscoveredService(CZeroconfBrowserAndroidDiscover
* browser
, CZeroconfBrowser::ZeroconfService
const& fcr_service
)
176 std::unique_lock
<CCriticalSection
> lock(m_data_guard
);
177 tDiscoveredServicesMap::iterator browserIt
= m_discovered_services
.find(browser
);
178 //search this service
179 std::vector
<std::pair
<ZeroconfService
, unsigned int> >& services
= browserIt
->second
;
180 std::vector
<std::pair
<ZeroconfService
, unsigned int> >::iterator serviceIt
= services
.begin();
181 for( ; serviceIt
!= services
.end(); ++serviceIt
)
182 if(serviceIt
->first
== fcr_service
)
184 if(serviceIt
!= services
.end())
188 if(!serviceIt
->second
)
190 //eventually remove the service
191 services
.erase(serviceIt
);
195 //looks like we missed the announce, no problem though..
200 /******************************************************************/
202 CZeroconfBrowserAndroidDiscover::CZeroconfBrowserAndroidDiscover(CZeroconfBrowserAndroid
* browser
)
203 : CJNIXBMCNsdManagerDiscoveryListener()
209 void CZeroconfBrowserAndroidDiscover::onDiscoveryStarted(const std::string
& serviceType
)
211 CLog::Log(LOGDEBUG
, "CZeroconfBrowserAndroidDiscover::onDiscoveryStarted type: {}", serviceType
);
215 void CZeroconfBrowserAndroidDiscover::onDiscoveryStopped(const std::string
& serviceType
)
217 CLog::Log(LOGDEBUG
, "CZeroconfBrowserAndroidDiscover::onDiscoveryStopped type: {}", serviceType
);
221 void CZeroconfBrowserAndroidDiscover::onServiceFound(const jni::CJNINsdServiceInfo
& serviceInfo
)
224 CZeroconfBrowser::ZeroconfService
s(serviceInfo
.getServiceName(), serviceInfo
.getServiceType(), "local");
225 jni::CJNISet
<jni::jhstring
> txtKey
= serviceInfo
.getAttributes().keySet();
226 jni::CJNIIterator
<jni::jhstring
> it
= txtKey
.iterator();
229 jni::jhstring k
= it
.next();
230 jni::jhbyteArray v
= serviceInfo
.getAttributes().get(k
);
232 std::string key
= jni::jcast
<std::string
>(k
);
233 std::vector
<char> vv
= jni::jcast
<std::vector
<char>>(v
);
234 std::string value
= std::string(vv
.begin(), vv
.end());
236 CLog::Log(LOGDEBUG
, "ZeroconfBrowserAndroid::onServiceFound: TXT record {} = {} ({})", key
,
241 "CZeroconfBrowserAndroidDiscover::onServiceFound found service named: {}, type: {}, "
243 s
.GetName(), s
.GetType(), s
.GetDomain());
244 m_browser
->addDiscoveredService(this, s
);
246 CGUIMessage
message(GUI_MSG_NOTIFY_ALL
, 0, 0, GUI_MSG_UPDATE_PATH
);
247 message
.SetStringParam("zeroconf://");
248 CServiceBroker::GetGUI()->GetWindowManager().SendThreadMessage(message
);
249 CLog::Log(LOGDEBUG
, "CZeroconfBrowserAndroidDiscover::onServiceFound sent gui update for path zeroconf://");
252 void CZeroconfBrowserAndroidDiscover::onServiceLost(const jni::CJNINsdServiceInfo
& serviceInfo
)
254 CLog::Log(LOGDEBUG
, "CZeroconfBrowserAndroidDiscover::onServiceLost name: {}, type: {}",
255 serviceInfo
.getServiceName(), serviceInfo
.getServiceType());
258 void CZeroconfBrowserAndroidDiscover::onStartDiscoveryFailed(const std::string
& serviceType
, int errorCode
)
260 CLog::Log(LOGDEBUG
, "CZeroconfBrowserAndroidDiscover::onStartDiscoveryFailed type: {}, error: {}",
261 serviceType
, errorCode
);
265 void CZeroconfBrowserAndroidDiscover::onStopDiscoveryFailed(const std::string
& serviceType
, int errorCode
)
267 CLog::Log(LOGDEBUG
, "CZeroconfBrowserAndroidDiscover::onStopDiscoveryFailed type: {}, error: {}",
268 serviceType
, errorCode
);
272 /***************************************/
274 CZeroconfBrowserAndroidResolve::CZeroconfBrowserAndroidResolve()
275 : CJNIXBMCNsdManagerResolveListener()
279 void CZeroconfBrowserAndroidResolve::onResolveFailed(const jni::CJNINsdServiceInfo
& serviceInfo
, int errorCode
)
282 "CZeroconfBrowserAndroidResolve::onResolveFailed name: {}, type: {}, error: {}",
283 serviceInfo
.getServiceName(), serviceInfo
.getServiceType(), errorCode
);
284 m_errorCode
= errorCode
;
285 m_resolutionDone
.Set();
288 void CZeroconfBrowserAndroidResolve::onServiceResolved(const jni::CJNINsdServiceInfo
& serviceInfo
)
290 CLog::Log(LOGDEBUG
, "CZeroconfBrowserAndroidResolve::onServiceResolved name: {}, type: {}",
291 serviceInfo
.getServiceName(), serviceInfo
.getServiceType());
293 m_retServiceInfo
= serviceInfo
;
294 m_resolutionDone
.Set();