[PVR][Estuary] Timer settings dialog: Show client name in timer type selection dialog...
[xbmc.git] / xbmc / platform / android / network / ZeroconfBrowserAndroid.cpp
blob67f4d5d0d3e5ce03dfe4433a1d8243564e7124f5
1 /*
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.
7 */
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"
19 #include <mutex>
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);
49 //store the browser
51 std::unique_lock<CCriticalSection> lock(m_data_guard);
52 m_service_browsers.insert(std::make_pair(fcr_service_type, discover));
54 return true;
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())
68 return false;
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);
84 delete discover;
86 return true;
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);
101 return ret;
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");
116 return false;
119 if (resolver.m_errorCode != -1)
121 CLog::Log(LOGERROR, "ZeroconfBrowserAndroid: DNSServiceResolve returned (error = {})",
122 resolver.m_errorCode);
123 return false;
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();
133 while (it.hasNext())
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)
166 break;
168 if(serviceIt == services.end())
169 services.emplace_back(fcr_service, 1);
170 else
171 ++serviceIt->second;
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)
183 break;
184 if(serviceIt != services.end())
186 //decrease refCount
187 --serviceIt->second;
188 if(!serviceIt->second)
190 //eventually remove the service
191 services.erase(serviceIt);
193 } else
195 //looks like we missed the announce, no problem though..
200 /******************************************************************/
202 CZeroconfBrowserAndroidDiscover::CZeroconfBrowserAndroidDiscover(CZeroconfBrowserAndroid* browser)
203 : CJNIXBMCNsdManagerDiscoveryListener()
204 , m_browser(browser)
205 , m_isActive(false)
209 void CZeroconfBrowserAndroidDiscover::onDiscoveryStarted(const std::string& serviceType)
211 CLog::Log(LOGDEBUG, "CZeroconfBrowserAndroidDiscover::onDiscoveryStarted type: {}", serviceType);
212 m_isActive = true;
215 void CZeroconfBrowserAndroidDiscover::onDiscoveryStopped(const std::string& serviceType)
217 CLog::Log(LOGDEBUG, "CZeroconfBrowserAndroidDiscover::onDiscoveryStopped type: {}", serviceType);
218 m_isActive = false;
221 void CZeroconfBrowserAndroidDiscover::onServiceFound(const jni::CJNINsdServiceInfo& serviceInfo)
223 //store the service
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();
227 while (it.hasNext())
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,
237 value, vv.size());
240 CLog::Log(LOGDEBUG,
241 "CZeroconfBrowserAndroidDiscover::onServiceFound found service named: {}, type: {}, "
242 "domain: {}",
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);
262 m_isActive = false;
265 void CZeroconfBrowserAndroidDiscover::onStopDiscoveryFailed(const std::string& serviceType, int errorCode)
267 CLog::Log(LOGDEBUG, "CZeroconfBrowserAndroidDiscover::onStopDiscoveryFailed type: {}, error: {}",
268 serviceType, errorCode);
269 m_isActive = false;
272 /***************************************/
274 CZeroconfBrowserAndroidResolve::CZeroconfBrowserAndroidResolve()
275 : CJNIXBMCNsdManagerResolveListener()
279 void CZeroconfBrowserAndroidResolve::onResolveFailed(const jni::CJNINsdServiceInfo& serviceInfo, int errorCode)
281 CLog::Log(LOGDEBUG,
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());
292 m_errorCode = -1;
293 m_retServiceInfo = serviceInfo;
294 m_resolutionDone.Set();