/* * 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. */ #include "NetworkServices.h" #include "ServiceBroker.h" #include "dialogs/GUIDialogKaiToast.h" #include "guilib/GUIComponent.h" #include "guilib/GUIWindowManager.h" #include "guilib/LocalizeStrings.h" #include "interfaces/json-rpc/JSONRPC.h" #include "messaging/ApplicationMessenger.h" #include "messaging/helpers/DialogHelper.h" #include "messaging/helpers/DialogOKHelper.h" #include "network/EventServer.h" #include "network/Network.h" #include "network/TCPServer.h" #include "settings/AdvancedSettings.h" #include "settings/Settings.h" #include "settings/SettingsComponent.h" #include "settings/lib/Setting.h" #include "settings/lib/SettingsManager.h" #include "utils/RssManager.h" #include "utils/SystemInfo.h" #include "utils/Variant.h" #include "utils/log.h" #include #ifdef TARGET_LINUX #include "Util.h" #endif #ifdef HAS_AIRPLAY #include "network/AirPlayServer.h" #endif // HAS_AIRPLAY #ifdef HAS_AIRTUNES #include "network/AirTunesServer.h" #endif // HAS_AIRTUNES #ifdef HAS_ZEROCONF #include "network/Zeroconf.h" #endif // HAS_ZEROCONF #ifdef HAS_UPNP #include "network/upnp/UPnP.h" #endif // HAS_UPNP #ifdef HAS_WEB_SERVER #include "network/WebServer.h" #include "network/httprequesthandler/HTTPImageHandler.h" #include "network/httprequesthandler/HTTPImageTransformationHandler.h" #include "network/httprequesthandler/HTTPVfsHandler.h" #include "network/httprequesthandler/HTTPJsonRpcHandler.h" #ifdef HAS_WEB_INTERFACE #ifdef HAS_PYTHON #include "network/httprequesthandler/HTTPPythonHandler.h" #endif #include "network/httprequesthandler/HTTPWebinterfaceHandler.h" #include "network/httprequesthandler/HTTPWebinterfaceAddonsHandler.h" #endif // HAS_WEB_INTERFACE #endif // HAS_WEB_SERVER #if defined(HAS_FILESYSTEM_SMB) #if defined(TARGET_WINDOWS) #include "platform/win32/network/WSDiscoveryWin32.h" #else // defined(TARGET_POSIX) #include "platform/posix/filesystem/SMBWSDiscovery.h" #endif #endif #if defined(TARGET_DARWIN_OSX) #include "platform/darwin/osx/XBMCHelper.h" #endif using namespace KODI::MESSAGING; using namespace JSONRPC; using namespace EVENTSERVER; #ifdef HAS_UPNP using namespace UPNP; #endif // HAS_UPNP using KODI::MESSAGING::HELPERS::DialogResponse; CNetworkServices::CNetworkServices() #ifdef HAS_WEB_SERVER : m_webserver(*new CWebServer), m_httpImageHandler(*new CHTTPImageHandler), m_httpImageTransformationHandler(*new CHTTPImageTransformationHandler), m_httpVfsHandler(*new CHTTPVfsHandler), m_httpJsonRpcHandler(*new CHTTPJsonRpcHandler) #ifdef HAS_WEB_INTERFACE #ifdef HAS_PYTHON , m_httpPythonHandler(*new CHTTPPythonHandler) #endif , m_httpWebinterfaceHandler(*new CHTTPWebinterfaceHandler) , m_httpWebinterfaceAddonsHandler(*new CHTTPWebinterfaceAddonsHandler) #endif // HAS_WEB_INTERFACE #endif // HAS_WEB_SERVER { #ifdef HAS_WEB_SERVER m_webserver.RegisterRequestHandler(&m_httpImageHandler); m_webserver.RegisterRequestHandler(&m_httpImageTransformationHandler); m_webserver.RegisterRequestHandler(&m_httpVfsHandler); m_webserver.RegisterRequestHandler(&m_httpJsonRpcHandler); #ifdef HAS_WEB_INTERFACE #ifdef HAS_PYTHON m_webserver.RegisterRequestHandler(&m_httpPythonHandler); #endif m_webserver.RegisterRequestHandler(&m_httpWebinterfaceAddonsHandler); m_webserver.RegisterRequestHandler(&m_httpWebinterfaceHandler); #endif // HAS_WEB_INTERFACE #endif // HAS_WEB_SERVER std::set settingSet{ CSettings::SETTING_SERVICES_WEBSERVER, CSettings::SETTING_SERVICES_WEBSERVERPORT, CSettings::SETTING_SERVICES_WEBSERVERAUTHENTICATION, CSettings::SETTING_SERVICES_WEBSERVERUSERNAME, CSettings::SETTING_SERVICES_WEBSERVERPASSWORD, CSettings::SETTING_SERVICES_WEBSERVERSSL, CSettings::SETTING_SERVICES_ZEROCONF, CSettings::SETTING_SERVICES_AIRPLAY, CSettings::SETTING_SERVICES_AIRPLAYVOLUMECONTROL, CSettings::SETTING_SERVICES_AIRPLAYVIDEOSUPPORT, CSettings::SETTING_SERVICES_USEAIRPLAYPASSWORD, CSettings::SETTING_SERVICES_AIRPLAYPASSWORD, CSettings::SETTING_SERVICES_UPNP, CSettings::SETTING_SERVICES_UPNPSERVER, CSettings::SETTING_SERVICES_UPNPRENDERER, CSettings::SETTING_SERVICES_UPNPCONTROLLER, CSettings::SETTING_SERVICES_ESENABLED, CSettings::SETTING_SERVICES_ESPORT, CSettings::SETTING_SERVICES_ESALLINTERFACES, CSettings::SETTING_SERVICES_ESINITIALDELAY, CSettings::SETTING_SERVICES_ESCONTINUOUSDELAY, CSettings::SETTING_SMB_WINSSERVER, CSettings::SETTING_SMB_WORKGROUP, CSettings::SETTING_SMB_MINPROTOCOL, CSettings::SETTING_SMB_MAXPROTOCOL, CSettings::SETTING_SMB_LEGACYSECURITY, CSettings::SETTING_SERVICES_WSDISCOVERY, }; m_settings = CServiceBroker::GetSettingsComponent()->GetSettings(); m_settings->GetSettingsManager()->RegisterCallback(this, settingSet); } CNetworkServices::~CNetworkServices() { m_settings->GetSettingsManager()->UnregisterCallback(this); #ifdef HAS_WEB_SERVER m_webserver.UnregisterRequestHandler(&m_httpImageHandler); delete &m_httpImageHandler; m_webserver.UnregisterRequestHandler(&m_httpImageTransformationHandler); delete &m_httpImageTransformationHandler; m_webserver.UnregisterRequestHandler(&m_httpVfsHandler); delete &m_httpVfsHandler; m_webserver.UnregisterRequestHandler(&m_httpJsonRpcHandler); delete &m_httpJsonRpcHandler; CJSONRPC::Cleanup(); #ifdef HAS_WEB_INTERFACE #ifdef HAS_PYTHON m_webserver.UnregisterRequestHandler(&m_httpPythonHandler); delete &m_httpPythonHandler; #endif m_webserver.UnregisterRequestHandler(&m_httpWebinterfaceAddonsHandler); delete &m_httpWebinterfaceAddonsHandler; m_webserver.UnregisterRequestHandler(&m_httpWebinterfaceHandler); delete &m_httpWebinterfaceHandler; #endif // HAS_WEB_INTERFACE delete &m_webserver; #endif // HAS_WEB_SERVER } bool CNetworkServices::OnSettingChanging(const std::shared_ptr& setting) { if (setting == NULL) return false; const std::string &settingId = setting->GetId(); #ifdef HAS_WEB_SERVER // Ask user to confirm disabling the authentication requirement, but not when the configuration // would be invalid when authentication was enabled (meaning that the change was triggered // automatically) if (settingId == CSettings::SETTING_SERVICES_WEBSERVERAUTHENTICATION && !std::static_pointer_cast(setting)->GetValue() && (!m_settings->GetBool(CSettings::SETTING_SERVICES_WEBSERVER) || (m_settings->GetBool(CSettings::SETTING_SERVICES_WEBSERVER) && !m_settings->GetString(CSettings::SETTING_SERVICES_WEBSERVERPASSWORD).empty())) && HELPERS::ShowYesNoDialogText(19098, 36634) != DialogResponse::CHOICE_YES) { // Leave it as-is return false; } if (settingId == CSettings::SETTING_SERVICES_WEBSERVER || settingId == CSettings::SETTING_SERVICES_WEBSERVERPORT || settingId == CSettings::SETTING_SERVICES_WEBSERVERSSL || settingId == CSettings::SETTING_SERVICES_WEBSERVERAUTHENTICATION || settingId == CSettings::SETTING_SERVICES_WEBSERVERUSERNAME || settingId == CSettings::SETTING_SERVICES_WEBSERVERPASSWORD) { if (IsWebserverRunning() && !StopWebserver()) return false; if (m_settings->GetBool(CSettings::SETTING_SERVICES_WEBSERVER)) { // Prevent changing to an invalid configuration if ((settingId == CSettings::SETTING_SERVICES_WEBSERVER || settingId == CSettings::SETTING_SERVICES_WEBSERVERAUTHENTICATION || settingId == CSettings::SETTING_SERVICES_WEBSERVERPASSWORD) && m_settings->GetBool(CSettings::SETTING_SERVICES_WEBSERVERAUTHENTICATION) && m_settings->GetString(CSettings::SETTING_SERVICES_WEBSERVERPASSWORD).empty()) { if (settingId == CSettings::SETTING_SERVICES_WEBSERVERAUTHENTICATION) { HELPERS::ShowOKDialogText(CVariant{257}, CVariant{36636}); } else { HELPERS::ShowOKDialogText(CVariant{257}, CVariant{36635}); } return false; } // Ask for confirmation when enabling the web server if (settingId == CSettings::SETTING_SERVICES_WEBSERVER && HELPERS::ShowYesNoDialogText(19098, 36632) != DialogResponse::CHOICE_YES) { // Revert change, do not start server return false; } if (!StartWebserver()) { HELPERS::ShowOKDialogText(CVariant{33101}, CVariant{33100}); return false; } } } else if (settingId == CSettings::SETTING_SERVICES_ESPORT || settingId == CSettings::SETTING_SERVICES_WEBSERVERPORT) return ValidatePort(std::static_pointer_cast(setting)->GetValue()); else #endif // HAS_WEB_SERVER #ifdef HAS_ZEROCONF if (settingId == CSettings::SETTING_SERVICES_ZEROCONF) { if (std::static_pointer_cast(setting)->GetValue()) return StartZeroconf(); #ifdef HAS_AIRPLAY else { // cannot disable if (IsAirPlayServerRunning() || IsAirTunesServerRunning()) { HELPERS::ShowOKDialogText(CVariant{1259}, CVariant{34303}); return false; } return StopZeroconf(); } #endif // HAS_AIRPLAY } else #endif // HAS_ZEROCONF #ifdef HAS_AIRPLAY if (settingId == CSettings::SETTING_SERVICES_AIRPLAY) { if (std::static_pointer_cast(setting)->GetValue()) { #ifdef HAS_ZEROCONF // AirPlay needs zeroconf if (!m_settings->GetBool(CSettings::SETTING_SERVICES_ZEROCONF)) { HELPERS::ShowOKDialogText(CVariant{1273}, CVariant{34302}); return false; } #endif //HAS_ZEROCONF // note - airtunesserver has to start before airplay server (ios7 client detection bug) #ifdef HAS_AIRTUNES if (!StartAirTunesServer()) { HELPERS::ShowOKDialogText(CVariant{1274}, CVariant{33100}); return false; } #endif //HAS_AIRTUNES if (!StartAirPlayServer()) { HELPERS::ShowOKDialogText(CVariant{1273}, CVariant{33100}); return false; } } else { bool ret = true; #ifdef HAS_AIRTUNES if (!StopAirTunesServer(true)) ret = false; #endif //HAS_AIRTUNES if (!StopAirPlayServer(true)) ret = false; if (!ret) return false; } } else if (settingId == CSettings::SETTING_SERVICES_AIRPLAYVIDEOSUPPORT) { if (std::static_pointer_cast(setting)->GetValue()) { if (!StartAirPlayServer()) { HELPERS::ShowOKDialogText(CVariant{1273}, CVariant{33100}); return false; } } else { if (!StopAirPlayServer(true)) return false; } } else if (settingId == CSettings::SETTING_SERVICES_AIRPLAYPASSWORD || settingId == CSettings::SETTING_SERVICES_USEAIRPLAYPASSWORD) { if (!m_settings->GetBool(CSettings::SETTING_SERVICES_AIRPLAY)) return false; if (!CAirPlayServer::SetCredentials(m_settings->GetBool(CSettings::SETTING_SERVICES_USEAIRPLAYPASSWORD), m_settings->GetString(CSettings::SETTING_SERVICES_AIRPLAYPASSWORD))) return false; } else #endif //HAS_AIRPLAY #ifdef HAS_UPNP if (settingId == CSettings::SETTING_SERVICES_UPNP) { if (std::static_pointer_cast(setting)->GetValue()) { StartUPnPClient(); StartUPnPController(); StartUPnPServer(); StartUPnPRenderer(); } else { StopUPnPRenderer(); StopUPnPServer(); StopUPnPController(); StopUPnPClient(); } } else if (settingId == CSettings::SETTING_SERVICES_UPNPSERVER) { if (std::static_pointer_cast(setting)->GetValue()) { if (!StartUPnPServer()) return false; // always stop and restart the client and controller if necessary StopUPnPClient(); StopUPnPController(); StartUPnPClient(); StartUPnPController(); } else return StopUPnPServer(); } else if (settingId == CSettings::SETTING_SERVICES_UPNPRENDERER) { if (std::static_pointer_cast(setting)->GetValue()) return StartUPnPRenderer(); else return StopUPnPRenderer(); } else if (settingId == CSettings::SETTING_SERVICES_UPNPCONTROLLER) { // always stop and restart StopUPnPController(); if (std::static_pointer_cast(setting)->GetValue()) return StartUPnPController(); } else #endif // HAS_UPNP if (settingId == CSettings::SETTING_SERVICES_ESENABLED) { if (std::static_pointer_cast(setting)->GetValue()) { bool result = true; if (!StartEventServer()) { HELPERS::ShowOKDialogText(CVariant{33102}, CVariant{33100}); result = false; } if (!StartJSONRPCServer()) { HELPERS::ShowOKDialogText(CVariant{33103}, CVariant{33100}); result = false; } return result; } else { bool result = true; result = StopEventServer(true, true); result &= StopJSONRPCServer(false); return result; } } else if (settingId == CSettings::SETTING_SERVICES_ESPORT) { // restart eventserver without asking user if (!StopEventServer(true, false)) return false; if (!StartEventServer()) { HELPERS::ShowOKDialogText(CVariant{33102}, CVariant{33100}); return false; } #if defined(TARGET_DARWIN_OSX) // reconfigure XBMCHelper for port changes XBMCHelper::GetInstance().Configure(); #endif // TARGET_DARWIN_OSX } else if (settingId == CSettings::SETTING_SERVICES_ESALLINTERFACES) { if (m_settings->GetBool(CSettings::SETTING_SERVICES_ESALLINTERFACES) && HELPERS::ShowYesNoDialogText(19098, 36633) != DialogResponse::CHOICE_YES) { // Revert change, do not start server return false; } if (m_settings->GetBool(CSettings::SETTING_SERVICES_ESENABLED)) { if (!StopEventServer(true, true)) return false; if (!StartEventServer()) { HELPERS::ShowOKDialogText(CVariant{33102}, CVariant{33100}); return false; } } if (m_settings->GetBool(CSettings::SETTING_SERVICES_ESENABLED)) { if (!StopJSONRPCServer(true)) return false; if (!StartJSONRPCServer()) { HELPERS::ShowOKDialogText(CVariant{33103}, CVariant{33100}); return false; } } } else if (settingId == CSettings::SETTING_SERVICES_ESINITIALDELAY || settingId == CSettings::SETTING_SERVICES_ESCONTINUOUSDELAY) { if (m_settings->GetBool(CSettings::SETTING_SERVICES_ESENABLED)) return RefreshEventServer(); } #if defined(HAS_FILESYSTEM_SMB) else if (settingId == CSettings::SETTING_SERVICES_WSDISCOVERY) { if (std::static_pointer_cast(setting)->GetValue()) { if (!StartWSDiscovery()) return false; } else return StopWSDiscovery(); } #endif // HAS_FILESYSTEM_SMB return true; } void CNetworkServices::OnSettingChanged(const std::shared_ptr& setting) { if (setting == NULL) return; const std::string& settingId = setting->GetId(); if (settingId == CSettings::SETTING_SMB_WINSSERVER || settingId == CSettings::SETTING_SMB_WORKGROUP || settingId == CSettings::SETTING_SMB_MINPROTOCOL || settingId == CSettings::SETTING_SMB_MAXPROTOCOL || settingId == CSettings::SETTING_SMB_LEGACYSECURITY) { // okey we really don't need to restart, only deinit samba, but that could be damn hard if something is playing //! @todo - General way of handling setting changes that require restart if (HELPERS::ShowYesNoDialogText(CVariant{14038}, CVariant{14039}) == DialogResponse::CHOICE_YES) { m_settings->Save(); CServiceBroker::GetAppMessenger()->PostMsg(TMSG_RESTARTAPP); } } } bool CNetworkServices::OnSettingUpdate(const std::shared_ptr& setting, const char* oldSettingId, const TiXmlNode* oldSettingNode) { if (setting == NULL) return false; const std::string &settingId = setting->GetId(); if (settingId == CSettings::SETTING_SERVICES_WEBSERVERUSERNAME) { // if webserverusername is xbmc and pw is not empty we treat it as altered // and don't change the username to kodi - part of rebrand if (m_settings->GetString(CSettings::SETTING_SERVICES_WEBSERVERUSERNAME) == "xbmc" && !m_settings->GetString(CSettings::SETTING_SERVICES_WEBSERVERPASSWORD).empty()) return true; } if (settingId == CSettings::SETTING_SERVICES_WEBSERVERPORT) { // if webserverport is default but webserver is activated then treat it as altered // and don't change the port to new value if (m_settings->GetBool(CSettings::SETTING_SERVICES_WEBSERVER)) return true; } return false; } void CNetworkServices::Start() { StartZeroconf(); if (m_settings->GetBool(CSettings::SETTING_SERVICES_UPNP)) StartUPnP(); if (m_settings->GetBool(CSettings::SETTING_SERVICES_ESENABLED) && !StartEventServer()) CGUIDialogKaiToast::QueueNotification(CGUIDialogKaiToast::Warning, g_localizeStrings.Get(33102), g_localizeStrings.Get(33100)); if (m_settings->GetBool(CSettings::SETTING_SERVICES_ESENABLED) && !StartJSONRPCServer()) CGUIDialogKaiToast::QueueNotification(CGUIDialogKaiToast::Warning, g_localizeStrings.Get(33103), g_localizeStrings.Get(33100)); #ifdef HAS_WEB_SERVER // Start web server after eventserver and JSON-RPC server, so users can use these interfaces // to confirm the warning message below if it is shown if (m_settings->GetBool(CSettings::SETTING_SERVICES_WEBSERVER)) { // services.webserverauthentication setting was added in Kodi v18 and requires a valid password // to be set, but on upgrade the setting will be activated automatically regardless of whether // a password was set before -> this can lead to an invalid configuration if (m_settings->GetBool(CSettings::SETTING_SERVICES_WEBSERVERAUTHENTICATION) && m_settings->GetString(CSettings::SETTING_SERVICES_WEBSERVERPASSWORD).empty()) { // Alert user to new default security settings in new Kodi version HELPERS::ShowOKDialogText(33101, 33104); // Fix settings: Disable web server m_settings->SetBool(CSettings::SETTING_SERVICES_WEBSERVER, false); // Bring user to settings screen where authentication can be configured properly CServiceBroker::GetGUI()->GetWindowManager().ActivateWindow( WINDOW_SETTINGS_SERVICE, std::vector{"services.webserverauthentication"}); } // Only try to start server if configuration is OK else if (!StartWebserver()) CGUIDialogKaiToast::QueueNotification( CGUIDialogKaiToast::Warning, g_localizeStrings.Get(33101), g_localizeStrings.Get(33100)); } #endif // HAS_WEB_SERVER // note - airtunesserver has to start before airplay server (ios7 client detection bug) StartAirTunesServer(); StartAirPlayServer(); StartRss(); StartWSDiscovery(); } void CNetworkServices::Stop(bool bWait) { if (bWait) { StopUPnP(bWait); StopZeroconf(); StopWebserver(); StopRss(); } StopEventServer(bWait, false); StopJSONRPCServer(bWait); StopAirPlayServer(bWait); StopAirTunesServer(bWait); StopWSDiscovery(); } bool CNetworkServices::StartServer(enum ESERVERS server, bool start) { auto settingsComponent = CServiceBroker::GetSettingsComponent(); if (!settingsComponent) return false; auto settings = CServiceBroker::GetSettingsComponent()->GetSettings(); if (!settings) return false; bool ret = false; switch (server) { case ES_WEBSERVER: // the callback will take care of starting/stopping webserver ret = settings->SetBool(CSettings::SETTING_SERVICES_WEBSERVER, start); break; case ES_AIRPLAYSERVER: // the callback will take care of starting/stopping airplay ret = settings->SetBool(CSettings::SETTING_SERVICES_AIRPLAY, start); break; case ES_JSONRPCSERVER: // the callback will take care of starting/stopping jsonrpc server ret = settings->SetBool(CSettings::SETTING_SERVICES_ESENABLED, start); break; case ES_UPNPSERVER: // the callback will take care of starting/stopping upnp server ret = settings->SetBool(CSettings::SETTING_SERVICES_UPNPSERVER, start); break; case ES_UPNPRENDERER: // the callback will take care of starting/stopping upnp renderer ret = settings->SetBool(CSettings::SETTING_SERVICES_UPNPRENDERER, start); break; case ES_EVENTSERVER: // the callback will take care of starting/stopping event server ret = settings->SetBool(CSettings::SETTING_SERVICES_ESENABLED, start); break; case ES_ZEROCONF: // the callback will take care of starting/stopping zeroconf ret = settings->SetBool(CSettings::SETTING_SERVICES_ZEROCONF, start); break; case ES_WSDISCOVERY: // the callback will take care of starting/stopping WS-Discovery ret = settings->SetBool(CSettings::SETTING_SERVICES_WSDISCOVERY, start); break; default: ret = false; break; } settings->Save(); return ret; } bool CNetworkServices::StartWebserver() { #ifdef HAS_WEB_SERVER if (!CServiceBroker::GetNetwork().IsAvailable()) return false; if (!m_settings->GetBool(CSettings::SETTING_SERVICES_WEBSERVER)) return false; if (m_settings->GetBool(CSettings::SETTING_SERVICES_WEBSERVERAUTHENTICATION) && m_settings->GetString(CSettings::SETTING_SERVICES_WEBSERVERPASSWORD).empty()) { CLog::Log(LOGERROR, "Tried to start webserver with invalid configuration (authentication " "enabled, but no password set"); return false; } int webPort = m_settings->GetInt(CSettings::SETTING_SERVICES_WEBSERVERPORT); if (!ValidatePort(webPort)) { CLog::Log(LOGERROR, "Cannot start Web Server on port {}", webPort); return false; } if (IsWebserverRunning()) return true; std::string username; std::string password; if (m_settings->GetBool(CSettings::SETTING_SERVICES_WEBSERVERAUTHENTICATION)) { username = m_settings->GetString(CSettings::SETTING_SERVICES_WEBSERVERUSERNAME); password = m_settings->GetString(CSettings::SETTING_SERVICES_WEBSERVERPASSWORD); } if (!m_webserver.Start(webPort, username, password)) return false; #ifdef HAS_ZEROCONF std::vector > txt; txt.emplace_back("txtvers", "1"); txt.emplace_back("uuid", CServiceBroker::GetSettingsComponent()->GetSettings()->GetString( CSettings::SETTING_SERVICES_DEVICEUUID)); // publish web frontend and API services #ifdef HAS_WEB_INTERFACE CZeroconf::GetInstance()->PublishService("servers.webserver", "_http._tcp", CSysInfo::GetDeviceName(), webPort, txt); #endif // HAS_WEB_INTERFACE CZeroconf::GetInstance()->PublishService("servers.jsonrpc-http", "_xbmc-jsonrpc-h._tcp", CSysInfo::GetDeviceName(), webPort, txt); #endif // HAS_ZEROCONF return true; #endif // HAS_WEB_SERVER return false; } bool CNetworkServices::IsWebserverRunning() { #ifdef HAS_WEB_SERVER return m_webserver.IsStarted(); #endif // HAS_WEB_SERVER return false; } bool CNetworkServices::StopWebserver() { #ifdef HAS_WEB_SERVER if (!IsWebserverRunning()) return true; if (!m_webserver.Stop() || m_webserver.IsStarted()) { CLog::Log(LOGWARNING, "Webserver: Failed to stop."); return false; } #ifdef HAS_ZEROCONF #ifdef HAS_WEB_INTERFACE CZeroconf::GetInstance()->RemoveService("servers.webserver"); #endif // HAS_WEB_INTERFACE CZeroconf::GetInstance()->RemoveService("servers.jsonrpc-http"); #endif // HAS_ZEROCONF return true; #endif // HAS_WEB_SERVER return false; } bool CNetworkServices::StartAirPlayServer() { if (!m_settings->GetBool(CSettings::SETTING_SERVICES_AIRPLAYVIDEOSUPPORT)) return true; #ifdef HAS_AIRPLAY if (!CServiceBroker::GetNetwork().IsAvailable() || !m_settings->GetBool(CSettings::SETTING_SERVICES_AIRPLAY)) return false; if (IsAirPlayServerRunning()) return true; if (!CAirPlayServer::StartServer(CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_airPlayPort, true)) return false; if (!CAirPlayServer::SetCredentials(m_settings->GetBool(CSettings::SETTING_SERVICES_USEAIRPLAYPASSWORD), m_settings->GetString(CSettings::SETTING_SERVICES_AIRPLAYPASSWORD))) return false; #ifdef HAS_ZEROCONF std::vector > txt; CNetworkInterface* iface = CServiceBroker::GetNetwork().GetFirstConnectedInterface(); txt.emplace_back("deviceid", iface != nullptr ? iface->GetMacAddress() : "FF:FF:FF:FF:FF:F2"); txt.emplace_back("model", "Xbmc,1"); txt.emplace_back("srcvers", AIRPLAY_SERVER_VERSION_STR); // for ios8 clients we need to announce mirroring support // else we won't get video urls anymore. // We also announce photo caching support (as it seems faster and // we have implemented it anyways). txt.emplace_back("features", "0x20F7"); CZeroconf::GetInstance()->PublishService("servers.airplay", "_airplay._tcp", CSysInfo::GetDeviceName(), CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_airPlayPort, txt); #endif // HAS_ZEROCONF return true; #endif // HAS_AIRPLAY return false; } bool CNetworkServices::IsAirPlayServerRunning() { #ifdef HAS_AIRPLAY return CAirPlayServer::IsRunning(); #endif // HAS_AIRPLAY return false; } bool CNetworkServices::StopAirPlayServer(bool bWait) { #ifdef HAS_AIRPLAY if (!IsAirPlayServerRunning()) return true; CAirPlayServer::StopServer(bWait); #ifdef HAS_ZEROCONF CZeroconf::GetInstance()->RemoveService("servers.airplay"); #endif // HAS_ZEROCONF return true; #endif // HAS_AIRPLAY return false; } bool CNetworkServices::StartAirTunesServer() { #ifdef HAS_AIRTUNES if (!CServiceBroker::GetNetwork().IsAvailable() || !m_settings->GetBool(CSettings::SETTING_SERVICES_AIRPLAY)) return false; if (IsAirTunesServerRunning()) return true; if (!CAirTunesServer::StartServer(CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_airTunesPort, true, m_settings->GetBool(CSettings::SETTING_SERVICES_USEAIRPLAYPASSWORD), m_settings->GetString(CSettings::SETTING_SERVICES_AIRPLAYPASSWORD))) { CLog::Log(LOGERROR, "Failed to start AirTunes Server"); return false; } return true; #endif // HAS_AIRTUNES return false; } bool CNetworkServices::IsAirTunesServerRunning() { #ifdef HAS_AIRTUNES return CAirTunesServer::IsRunning(); #endif // HAS_AIRTUNES return false; } bool CNetworkServices::StopAirTunesServer(bool bWait) { #ifdef HAS_AIRTUNES if (!IsAirTunesServerRunning()) return true; CAirTunesServer::StopServer(bWait); return true; #endif // HAS_AIRTUNES return false; } bool CNetworkServices::StartJSONRPCServer() { if (!m_settings->GetBool(CSettings::SETTING_SERVICES_ESENABLED)) return false; if (IsJSONRPCServerRunning()) return true; if (!CTCPServer::StartServer(CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_jsonTcpPort, m_settings->GetBool(CSettings::SETTING_SERVICES_ESALLINTERFACES))) return false; #ifdef HAS_ZEROCONF std::vector > txt; txt.emplace_back("txtvers", "1"); txt.emplace_back("uuid", CServiceBroker::GetSettingsComponent()->GetSettings()->GetString( CSettings::SETTING_SERVICES_DEVICEUUID)); CZeroconf::GetInstance()->PublishService("servers.jsonrpc-tpc", "_xbmc-jsonrpc._tcp", CSysInfo::GetDeviceName(), CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_jsonTcpPort, txt); #endif // HAS_ZEROCONF return true; } bool CNetworkServices::IsJSONRPCServerRunning() { return CTCPServer::IsRunning(); } bool CNetworkServices::StopJSONRPCServer(bool bWait) { if (!IsJSONRPCServerRunning()) return true; CTCPServer::StopServer(bWait); #ifdef HAS_ZEROCONF CZeroconf::GetInstance()->RemoveService("servers.jsonrpc-tcp"); #endif // HAS_ZEROCONF return true; } bool CNetworkServices::StartEventServer() { if (!m_settings->GetBool(CSettings::SETTING_SERVICES_ESENABLED)) return false; if (IsEventServerRunning()) return true; CEventServer* server = CEventServer::GetInstance(); if (!server) { CLog::Log(LOGERROR, "ES: Out of memory"); return false; } server->StartServer(); return true; } bool CNetworkServices::IsEventServerRunning() { return CEventServer::GetInstance()->Running(); } bool CNetworkServices::StopEventServer(bool bWait, bool promptuser) { if (!IsEventServerRunning()) return true; CEventServer* server = CEventServer::GetInstance(); if (!server) { CLog::Log(LOGERROR, "ES: Out of memory"); return false; } if (promptuser) { if (server->GetNumberOfClients() > 0) { if (HELPERS::ShowYesNoDialogText(CVariant{13140}, CVariant{13141}, CVariant{""}, CVariant{""}, 10000) != DialogResponse::CHOICE_YES) { CLog::Log(LOGINFO, "ES: Not stopping event server"); return false; } } CLog::Log(LOGINFO, "ES: Stopping event server with confirmation"); CEventServer::GetInstance()->StopServer(true); } else { if (!bWait) CLog::Log(LOGINFO, "ES: Stopping event server"); CEventServer::GetInstance()->StopServer(bWait); } return true; } bool CNetworkServices::RefreshEventServer() { if (!m_settings->GetBool(CSettings::SETTING_SERVICES_ESENABLED)) return false; if (!IsEventServerRunning()) return false; CEventServer::GetInstance()->RefreshSettings(); return true; } bool CNetworkServices::StartUPnP() { bool ret = false; #ifdef HAS_UPNP ret |= StartUPnPClient(); if (m_settings->GetBool(CSettings::SETTING_SERVICES_UPNPSERVER)) { ret |= StartUPnPServer(); } if (m_settings->GetBool(CSettings::SETTING_SERVICES_UPNPCONTROLLER)) { ret |= StartUPnPController(); } if (m_settings->GetBool(CSettings::SETTING_SERVICES_UPNPRENDERER)) { ret |= StartUPnPRenderer(); } #endif // HAS_UPNP return ret; } bool CNetworkServices::StopUPnP(bool bWait) { #ifdef HAS_UPNP if (!CUPnP::IsInstantiated()) return true; CLog::Log(LOGINFO, "stopping upnp"); CUPnP::ReleaseInstance(bWait); return true; #endif // HAS_UPNP return false; } bool CNetworkServices::StartUPnPClient() { #ifdef HAS_UPNP if (!m_settings->GetBool(CSettings::SETTING_SERVICES_UPNP)) return false; CLog::Log(LOGINFO, "starting upnp client"); CUPnP::GetInstance()->StartClient(); return IsUPnPClientRunning(); #endif // HAS_UPNP return false; } bool CNetworkServices::IsUPnPClientRunning() { #ifdef HAS_UPNP return CUPnP::GetInstance()->IsClientStarted(); #endif // HAS_UPNP return false; } bool CNetworkServices::StopUPnPClient() { #ifdef HAS_UPNP if (!IsUPnPClientRunning()) return true; CLog::Log(LOGINFO, "stopping upnp client"); CUPnP::GetInstance()->StopClient(); return true; #endif // HAS_UPNP return false; } bool CNetworkServices::StartUPnPController() { #ifdef HAS_UPNP if (!m_settings->GetBool(CSettings::SETTING_SERVICES_UPNPCONTROLLER) || !m_settings->GetBool(CSettings::SETTING_SERVICES_UPNPSERVER) || !m_settings->GetBool(CSettings::SETTING_SERVICES_UPNP)) return false; CLog::Log(LOGINFO, "starting upnp controller"); CUPnP::GetInstance()->StartController(); return IsUPnPControllerRunning(); #endif // HAS_UPNP return false; } bool CNetworkServices::IsUPnPControllerRunning() { #ifdef HAS_UPNP return CUPnP::GetInstance()->IsControllerStarted(); #endif // HAS_UPNP return false; } bool CNetworkServices::StopUPnPController() { #ifdef HAS_UPNP if (!IsUPnPControllerRunning()) return true; CLog::Log(LOGINFO, "stopping upnp controller"); CUPnP::GetInstance()->StopController(); return true; #endif // HAS_UPNP return false; } bool CNetworkServices::StartUPnPRenderer() { #ifdef HAS_UPNP if (!m_settings->GetBool(CSettings::SETTING_SERVICES_UPNPRENDERER) || !m_settings->GetBool(CSettings::SETTING_SERVICES_UPNP)) return false; CLog::Log(LOGINFO, "starting upnp renderer"); return CUPnP::GetInstance()->StartRenderer(); #endif // HAS_UPNP return false; } bool CNetworkServices::IsUPnPRendererRunning() { #ifdef HAS_UPNP return CUPnP::GetInstance()->IsInstantiated(); #endif // HAS_UPNP return false; } bool CNetworkServices::StopUPnPRenderer() { #ifdef HAS_UPNP if (!IsUPnPRendererRunning()) return true; CLog::Log(LOGINFO, "stopping upnp renderer"); CUPnP::GetInstance()->StopRenderer(); return true; #endif // HAS_UPNP return false; } bool CNetworkServices::StartUPnPServer() { #ifdef HAS_UPNP if (!m_settings->GetBool(CSettings::SETTING_SERVICES_UPNPSERVER) || !m_settings->GetBool(CSettings::SETTING_SERVICES_UPNP)) return false; CLog::Log(LOGINFO, "starting upnp server"); return CUPnP::GetInstance()->StartServer(); #endif // HAS_UPNP return false; } bool CNetworkServices::IsUPnPServerRunning() { #ifdef HAS_UPNP return CUPnP::GetInstance()->IsInstantiated(); #endif // HAS_UPNP return false; } bool CNetworkServices::StopUPnPServer() { #ifdef HAS_UPNP if (!IsUPnPServerRunning()) return true; StopUPnPController(); CLog::Log(LOGINFO, "stopping upnp server"); CUPnP::GetInstance()->StopServer(); return true; #endif // HAS_UPNP return false; } bool CNetworkServices::StartRss() { if (IsRssRunning()) return true; CRssManager::GetInstance().Start(); return true; } bool CNetworkServices::IsRssRunning() { return CRssManager::GetInstance().IsActive(); } bool CNetworkServices::StopRss() { if (!IsRssRunning()) return true; CRssManager::GetInstance().Stop(); return true; } bool CNetworkServices::StartZeroconf() { #ifdef HAS_ZEROCONF if (!m_settings->GetBool(CSettings::SETTING_SERVICES_ZEROCONF)) return false; if (IsZeroconfRunning()) return true; CLog::Log(LOGINFO, "starting zeroconf publishing"); return CZeroconf::GetInstance()->Start(); #endif // HAS_ZEROCONF return false; } bool CNetworkServices::IsZeroconfRunning() { #ifdef HAS_ZEROCONF return CZeroconf::GetInstance()->IsStarted(); #endif // HAS_ZEROCONF return false; } bool CNetworkServices::StopZeroconf() { #ifdef HAS_ZEROCONF if (!IsZeroconfRunning()) return true; CLog::Log(LOGINFO, "stopping zeroconf publishing"); CZeroconf::GetInstance()->Stop(); return true; #endif // HAS_ZEROCONF return false; } bool CNetworkServices::StartWSDiscovery() { #if defined(HAS_FILESYSTEM_SMB) if (!m_settings->GetBool(CSettings::SETTING_SERVICES_WSDISCOVERY)) return false; if (IsWSDiscoveryRunning()) return true; return CServiceBroker::GetWSDiscovery().StartServices(); #endif // HAS_FILESYSTEM_SMB return false; } bool CNetworkServices::IsWSDiscoveryRunning() { #if defined(HAS_FILESYSTEM_SMB) return CServiceBroker::GetWSDiscovery().IsRunning(); #endif // HAS_FILESYSTEM_SMB return false; } bool CNetworkServices::StopWSDiscovery() { #if defined(HAS_FILESYSTEM_SMB) if (!IsWSDiscoveryRunning()) return true; CServiceBroker::GetWSDiscovery().StopServices(); return true; #endif // HAS_FILESYSTEM_SMB return false; } bool CNetworkServices::ValidatePort(int port) { if (port <= 0 || port > 65535) return false; #ifdef TARGET_LINUX if (!CUtil::CanBindPrivileged() && (port < 1024)) return false; #endif return true; }