From c04dcc2e7d834218ef2d4194331e383402495ae1 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Wed, 10 Apr 2024 20:07:22 +0200 Subject: Adding upstream version 2:20.4+dfsg. Signed-off-by: Daniel Baumann --- xbmc/network/NetworkServices.cpp | 1267 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 1267 insertions(+) create mode 100644 xbmc/network/NetworkServices.cpp (limited to 'xbmc/network/NetworkServices.cpp') diff --git a/xbmc/network/NetworkServices.cpp b/xbmc/network/NetworkServices.cpp new file mode 100644 index 0000000..4009433 --- /dev/null +++ b/xbmc/network/NetworkServices.cpp @@ -0,0 +1,1267 @@ +/* + * 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; +} -- cgit v1.2.3