2 * Copyright (C) 2005-2013 Team XBMC
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, see
17 * <http://www.gnu.org/licenses/>.
21 #include "NetworkServices.h"
22 #include "Application.h"
23 #include "ApplicationMessenger.h"
24 #include "GUIInfoManager.h"
28 #include "dialogs/GUIDialogKaiToast.h"
29 #include "dialogs/GUIDialogOK.h"
30 #include "dialogs/GUIDialogYesNo.h"
31 #include "guilib/LocalizeStrings.h"
32 #include "network/Network.h"
35 #include "network/AirPlayServer.h"
39 #include "network/AirTunesServer.h"
40 #endif // HAS_AIRTUNES
42 #ifdef HAS_EVENT_SERVER
43 #include "network/EventServer.h"
44 #endif // HAS_EVENT_SERVER
47 #include "interfaces/json-rpc/JSONRPC.h"
48 #include "network/TCPServer.h"
52 #include "network/Zeroconf.h"
53 #endif // HAS_ZEROCONF
56 #include "network/upnp/UPnP.h"
60 #include "network/WebServer.h"
61 #include "network/httprequesthandler/HTTPImageHandler.h"
62 #include "network/httprequesthandler/HTTPVfsHandler.h"
64 #include "network/httprequesthandler/HTTPJsonRpcHandler.h"
66 #ifdef HAS_WEB_INTERFACE
67 #include "network/httprequesthandler/HTTPWebinterfaceHandler.h"
68 #include "network/httprequesthandler/HTTPWebinterfaceAddonsHandler.h"
69 #endif // HAS_WEB_INTERFACE
70 #endif // HAS_WEB_SERVER
72 #if defined(TARGET_DARWIN_OSX)
73 #include "osx/XBMCHelper.h"
76 #include "settings/AdvancedSettings.h"
77 #include "settings/lib/Setting.h"
78 #include "settings/Settings.h"
79 #include "utils/log.h"
80 #include "utils/RssManager.h"
84 using namespace JSONRPC;
86 #ifdef HAS_EVENT_SERVER
87 using namespace EVENTSERVER;
88 #endif // HAS_EVENT_SERVER
93 CNetworkServices::CNetworkServices()
96 m_webserver(*new CWebServer),
97 m_httpImageHandler(*new CHTTPImageHandler),
98 m_httpVfsHandler(*new CHTTPVfsHandler)
100 , m_httpJsonRpcHandler(*new CHTTPJsonRpcHandler)
101 #endif // HAS_JSONRPC
102 #ifdef HAS_WEB_INTERFACE
103 , m_httpWebinterfaceHandler(*new CHTTPWebinterfaceHandler)
104 , m_httpWebinterfaceAddonsHandler(*new CHTTPWebinterfaceAddonsHandler)
105 #endif // HAS_WEB_INTERFACE
106 #endif // HAS_WEB_SERVER
108 #ifdef HAS_WEB_SERVER
109 CWebServer::RegisterRequestHandler(&m_httpImageHandler);
110 CWebServer::RegisterRequestHandler(&m_httpVfsHandler);
112 CWebServer::RegisterRequestHandler(&m_httpJsonRpcHandler);
113 #endif // HAS_JSONRPC
114 #ifdef HAS_WEB_INTERFACE
115 CWebServer::RegisterRequestHandler(&m_httpWebinterfaceAddonsHandler);
116 CWebServer::RegisterRequestHandler(&m_httpWebinterfaceHandler);
117 #endif // HAS_WEB_INTERFACE
118 #endif // HAS_WEB_SERVER
121 CNetworkServices::~CNetworkServices()
123 #ifdef HAS_WEB_SERVER
124 CWebServer::UnregisterRequestHandler(&m_httpImageHandler);
125 delete &m_httpImageHandler;
126 CWebServer::UnregisterRequestHandler(&m_httpVfsHandler);
127 delete &m_httpVfsHandler;
129 CWebServer::UnregisterRequestHandler(&m_httpJsonRpcHandler);
130 delete &m_httpJsonRpcHandler;
132 #endif // HAS_JSONRPC
133 #ifdef HAS_WEB_INTERFACE
134 CWebServer::UnregisterRequestHandler(&m_httpWebinterfaceAddonsHandler);
135 delete &m_httpWebinterfaceAddonsHandler;
136 CWebServer::UnregisterRequestHandler(&m_httpWebinterfaceHandler);
137 delete &m_httpWebinterfaceHandler;
138 #endif // HAS_WEB_INTERFACE
140 #endif // HAS_WEB_SERVER
143 CNetworkServices& CNetworkServices::Get()
145 static CNetworkServices sNetworkServices;
146 return sNetworkServices;
149 bool CNetworkServices::OnSettingChanging(const CSetting *setting)
154 const std::string &settingId = setting->GetId();
155 #ifdef HAS_WEB_SERVER
156 if (settingId == "services.webserver" ||
157 settingId == "services.webserverport")
159 if (IsWebserverRunning() && !StopWebserver())
162 if (CSettings::Get().GetBool("services.webserver"))
164 if (!StartWebserver())
166 CGUIDialogOK::ShowAndGetInput(g_localizeStrings.Get(33101), "", g_localizeStrings.Get(33100), "");
171 else if (settingId == "services.esport" ||
172 settingId == "services.webserverport")
173 return ValidatePort(((CSettingInt*)setting)->GetValue());
175 #endif // HAS_WEB_SERVER
178 if (settingId == "services.zeroconf")
180 if (((CSettingBool*)setting)->GetValue())
181 return StartZeroconf();
186 if (IsAirPlayServerRunning() || IsAirTunesServerRunning())
188 CGUIDialogOK::ShowAndGetInput(g_localizeStrings.Get(1259), g_localizeStrings.Get(34303), g_localizeStrings.Get(34304), "");
192 return StopZeroconf();
194 #endif // HAS_AIRPLAY
197 #endif // HAS_ZEROCONF
200 if (settingId == "services.airplay")
202 if (((CSettingBool*)setting)->GetValue())
205 // AirPlay needs zeroconf
206 if (!CSettings::Get().GetBool("services.zeroconf"))
208 CGUIDialogOK::ShowAndGetInput(g_localizeStrings.Get(1273), g_localizeStrings.Get(33100), g_localizeStrings.Get(34302), "");
211 #endif //HAS_ZEROCONF
213 // note - airtunesserver has to start before airplay server (ios7 client detection bug)
215 if (!StartAirTunesServer())
217 CGUIDialogOK::ShowAndGetInput(g_localizeStrings.Get(1274), "", g_localizeStrings.Get(33100), "");
220 #endif //HAS_AIRTUNES
222 if (!StartAirPlayServer())
224 CGUIDialogOK::ShowAndGetInput(g_localizeStrings.Get(1273), "", g_localizeStrings.Get(33100), "");
232 if (!StopAirTunesServer(true))
234 #endif //HAS_AIRTUNES
236 if (!StopAirPlayServer(true))
243 else if (settingId == "services.airplaypassword" ||
244 settingId == "services.useairplaypassword")
246 if (!CSettings::Get().GetBool("services.airplay"))
249 if (!CAirPlayServer::SetCredentials(CSettings::Get().GetBool("services.useairplaypassword"),
250 CSettings::Get().GetString("services.airplaypassword")))
257 if (settingId == "services.upnpserver")
259 if (((CSettingBool*)setting)->GetValue())
261 if (!StartUPnPServer())
264 // always stop and restart the client if necessary
269 return StopUPnPServer();
271 else if (settingId == "services.upnprenderer")
273 if (((CSettingBool*)setting)->GetValue())
274 return StartUPnPRenderer();
276 return StopUPnPRenderer();
278 else if (settingId == "services.upnpcontroller")
280 // always stop and restart
282 if (((CSettingBool*)setting)->GetValue())
283 return StartUPnPClient();
288 if (settingId == "services.esenabled")
290 #ifdef HAS_EVENT_SERVER
291 if (((CSettingBool*)setting)->GetValue())
293 if (!StartEventServer())
295 CGUIDialogOK::ShowAndGetInput(g_localizeStrings.Get(33102), "", g_localizeStrings.Get(33100), "");
300 return StopEventServer(true, true);
301 #endif // HAS_EVENT_SERVER
304 if (CSettings::Get().GetBool("services.esenabled"))
306 if (!StartJSONRPCServer())
308 CGUIDialogOK::ShowAndGetInput(g_localizeStrings.Get(33103), "", g_localizeStrings.Get(33100), "");
313 return StopJSONRPCServer(false);
314 #endif // HAS_JSONRPC
316 else if (settingId == "services.esport")
318 #ifdef HAS_EVENT_SERVER
319 // restart eventserver without asking user
320 if (!StopEventServer(true, false))
323 if (!StartEventServer())
325 CGUIDialogOK::ShowAndGetInput(g_localizeStrings.Get(33102), "", g_localizeStrings.Get(33100), "");
329 #if defined(TARGET_DARWIN_OSX)
330 // reconfigure XBMCHelper for port changes
331 XBMCHelper::GetInstance().Configure();
332 #endif // TARGET_DARWIN_OSX
333 #endif // HAS_EVENT_SERVER
335 else if (settingId == "services.esallinterfaces")
337 #ifdef HAS_EVENT_SERVER
338 if (CSettings::Get().GetBool("services.esenabled"))
340 if (!StopEventServer(true, true))
343 if (!StartEventServer())
345 CGUIDialogOK::ShowAndGetInput(g_localizeStrings.Get(33102), "", g_localizeStrings.Get(33100), "");
349 #endif // HAS_EVENT_SERVER
352 if (CSettings::Get().GetBool("services.esenabled"))
354 if (!StartJSONRPCServer())
356 CGUIDialogOK::ShowAndGetInput(g_localizeStrings.Get(33103), "", g_localizeStrings.Get(33100), "");
360 #endif // HAS_JSONRPC
363 #ifdef HAS_EVENT_SERVER
364 else if (settingId == "services.esinitialdelay" ||
365 settingId == "services.escontinuousdelay")
367 if (CSettings::Get().GetBool("services.esenabled"))
368 return RefreshEventServer();
370 #endif // HAS_EVENT_SERVER
375 void CNetworkServices::OnSettingChanged(const CSetting *setting)
380 const std::string &settingId = setting->GetId();
381 #ifdef HAS_WEB_SERVER
382 if (settingId == "services.webserverusername" ||
383 settingId == "services.webserverpassword")
385 m_webserver.SetCredentials(CSettings::Get().GetString("services.webserverusername"),
386 CSettings::Get().GetString("services.webserverpassword"));
389 #endif // HAS_WEB_SERVER
390 if (settingId == "smb.winsserver" ||
391 settingId == "smb.workgroup")
393 // okey we really don't need to restart, only deinit samba, but that could be damn hard if something is playing
394 // TODO - General way of handling setting changes that require restart
395 if (CGUIDialogYesNo::ShowAndGetInput(14038, 14039, 14040, -1, -1))
397 CSettings::Get().Save();
398 CApplicationMessenger::Get().RestartApp();
403 void CNetworkServices::Start()
406 #ifdef HAS_WEB_SERVER
407 if (CSettings::Get().GetBool("services.webserver") && !StartWebserver())
408 CGUIDialogKaiToast::QueueNotification(CGUIDialogKaiToast::Warning, g_localizeStrings.Get(33101), g_localizeStrings.Get(33100));
409 #endif // HAS_WEB_SERVER
411 if (CSettings::Get().GetBool("services.esenabled") && !StartEventServer())
412 CGUIDialogKaiToast::QueueNotification(CGUIDialogKaiToast::Warning, g_localizeStrings.Get(33102), g_localizeStrings.Get(33100));
413 if (CSettings::Get().GetBool("services.esenabled") && !StartJSONRPCServer())
414 CGUIDialogKaiToast::QueueNotification(CGUIDialogKaiToast::Warning, g_localizeStrings.Get(33103), g_localizeStrings.Get(33100));
416 // note - airtunesserver has to start before airplay server (ios7 client detection bug)
417 StartAirTunesServer();
418 StartAirPlayServer();
422 void CNetworkServices::Stop(bool bWait)
432 StopEventServer(bWait, false);
433 StopJSONRPCServer(bWait);
434 StopAirPlayServer(bWait);
435 StopAirTunesServer(bWait);
438 bool CNetworkServices::StartWebserver()
440 #ifdef HAS_WEB_SERVER
441 if (!g_application.getNetwork().IsAvailable())
444 if (!CSettings::Get().GetBool("services.webserver"))
447 int webPort = CSettings::Get().GetInt("services.webserverport");
448 if (!ValidatePort(webPort))
450 CLog::Log(LOGERROR, "Cannot start Web Server on port %i", webPort);
454 if (IsWebserverRunning())
457 CLog::Log(LOGNOTICE, "Webserver: Starting...");
458 if (!m_webserver.Start(webPort, CSettings::Get().GetString("services.webserverusername"), CSettings::Get().GetString("services.webserverpassword")))
462 std::vector<std::pair<std::string, std::string> > txt;
463 // publish web frontend and API services
464 #ifdef HAS_WEB_INTERFACE
465 CZeroconf::GetInstance()->PublishService("servers.webserver", "_http._tcp", g_infoManager.GetLabel(SYSTEM_FRIENDLY_NAME), webPort, txt);
466 #endif // HAS_WEB_INTERFACE
468 CZeroconf::GetInstance()->PublishService("servers.jsonrpc-http", "_xbmc-jsonrpc-h._tcp", g_infoManager.GetLabel(SYSTEM_FRIENDLY_NAME), webPort, txt);
469 #endif // HAS_JSONRPC
470 #endif // HAS_ZEROCONF
473 #endif // HAS_WEB_SERVER
477 bool CNetworkServices::IsWebserverRunning()
479 #ifdef HAS_WEB_SERVER
480 return m_webserver.IsStarted();
481 #endif // HAS_WEB_SERVER
485 bool CNetworkServices::StopWebserver()
487 #ifdef HAS_WEB_SERVER
488 if (!IsWebserverRunning())
491 CLog::Log(LOGNOTICE, "Webserver: Stopping...");
492 if (!m_webserver.Stop() || m_webserver.IsStarted())
494 CLog::Log(LOGWARNING, "Webserver: Failed to stop.");
498 CLog::Log(LOGNOTICE, "Webserver: Stopped...");
500 #ifdef HAS_WEB_INTERFACE
501 CZeroconf::GetInstance()->RemoveService("servers.webserver");
502 #endif // HAS_WEB_INTERFACE
504 CZeroconf::GetInstance()->RemoveService("servers.jsonrpc-http");
505 #endif // HAS_JSONRPC
506 #endif // HAS_ZEROCONF
509 #endif // HAS_WEB_SERVER
513 bool CNetworkServices::StartAirPlayServer()
516 if (!g_application.getNetwork().IsAvailable() || !CSettings::Get().GetBool("services.airplay"))
519 if (IsAirPlayServerRunning())
522 if (!CAirPlayServer::StartServer(g_advancedSettings.m_airPlayPort, true))
525 if (!CAirPlayServer::SetCredentials(CSettings::Get().GetBool("services.useairplaypassword"),
526 CSettings::Get().GetString("services.airplaypassword")))
530 std::vector<std::pair<std::string, std::string> > txt;
531 CNetworkInterface* iface = g_application.getNetwork().GetFirstConnectedInterface();
532 txt.push_back(make_pair("deviceid", iface != NULL ? iface->GetMacAddress() : "FF:FF:FF:FF:FF:F2"));
533 txt.push_back(make_pair("features", "0x77"));
534 txt.push_back(make_pair("model", "Xbmc,1"));
535 txt.push_back(make_pair("srcvers", AIRPLAY_SERVER_VERSION_STR));
536 CZeroconf::GetInstance()->PublishService("servers.airplay", "_airplay._tcp", g_infoManager.GetLabel(SYSTEM_FRIENDLY_NAME), g_advancedSettings.m_airPlayPort, txt);
537 #endif // HAS_ZEROCONF
540 #endif // HAS_AIRPLAY
544 bool CNetworkServices::IsAirPlayServerRunning()
547 return CAirPlayServer::IsRunning();
548 #endif // HAS_AIRPLAY
552 bool CNetworkServices::StopAirPlayServer(bool bWait)
555 if (!IsAirPlayServerRunning())
558 CAirPlayServer::StopServer(bWait);
561 CZeroconf::GetInstance()->RemoveService("servers.airplay");
562 #endif // HAS_ZEROCONF
565 #endif // HAS_AIRPLAY
569 bool CNetworkServices::StartAirTunesServer()
572 if (!g_application.getNetwork().IsAvailable() || !CSettings::Get().GetBool("services.airplay"))
575 if (IsAirTunesServerRunning())
578 if (!CAirTunesServer::StartServer(g_advancedSettings.m_airTunesPort, true,
579 CSettings::Get().GetBool("services.useairplaypassword"),
580 CSettings::Get().GetString("services.airplaypassword")))
582 CLog::Log(LOGERROR, "Failed to start AirTunes Server");
587 #endif // HAS_AIRTUNES
591 bool CNetworkServices::IsAirTunesServerRunning()
594 return CAirTunesServer::IsRunning();
595 #endif // HAS_AIRTUNES
599 bool CNetworkServices::StopAirTunesServer(bool bWait)
602 if (!IsAirTunesServerRunning())
605 CAirTunesServer::StopServer(bWait);
607 #endif // HAS_AIRTUNES
611 bool CNetworkServices::StartJSONRPCServer()
614 if (!CSettings::Get().GetBool("services.esenabled"))
617 if (IsJSONRPCServerRunning())
620 if (!CTCPServer::StartServer(g_advancedSettings.m_jsonTcpPort, CSettings::Get().GetBool("services.esallinterfaces")))
624 std::vector<std::pair<std::string, std::string> > txt;
625 CZeroconf::GetInstance()->PublishService("servers.jsonrpc-tpc", "_xbmc-jsonrpc._tcp", g_infoManager.GetLabel(SYSTEM_FRIENDLY_NAME), g_advancedSettings.m_jsonTcpPort, txt);
626 #endif // HAS_ZEROCONF
629 #endif // HAS_JSONRPC
633 bool CNetworkServices::IsJSONRPCServerRunning()
636 return CTCPServer::IsRunning();
637 #endif // HAS_JSONRPC
641 bool CNetworkServices::StopJSONRPCServer(bool bWait)
644 if (!IsJSONRPCServerRunning())
647 CTCPServer::StopServer(bWait);
650 CZeroconf::GetInstance()->RemoveService("servers.jsonrpc-tcp");
651 #endif // HAS_ZEROCONF
654 #endif // HAS_JSONRPC
658 bool CNetworkServices::StartEventServer()
660 #ifdef HAS_EVENT_SERVER
661 if (!CSettings::Get().GetBool("services.esenabled"))
664 if (IsEventServerRunning())
667 CEventServer* server = CEventServer::GetInstance();
670 CLog::Log(LOGERROR, "ES: Out of memory");
674 CLog::Log(LOGNOTICE, "ES: Starting event server");
675 server->StartServer();
678 #endif // HAS_EVENT_SERVER
682 bool CNetworkServices::IsEventServerRunning()
684 #ifdef HAS_EVENT_SERVER
685 return CEventServer::GetInstance()->Running();
686 #endif // HAS_EVENT_SERVER
690 bool CNetworkServices::StopEventServer(bool bWait, bool promptuser)
692 #ifdef HAS_EVENT_SERVER
693 if (!IsEventServerRunning())
696 CEventServer* server = CEventServer::GetInstance();
699 CLog::Log(LOGERROR, "ES: Out of memory");
705 if (server->GetNumberOfClients() > 0)
707 bool cancelled = false;
708 if (!CGUIDialogYesNo::ShowAndGetInput(13140, 13141, 13142, 20022,
709 -1, -1, cancelled, 10000)
712 CLog::Log(LOGNOTICE, "ES: Not stopping event server");
716 CLog::Log(LOGNOTICE, "ES: Stopping event server with confirmation");
718 CEventServer::GetInstance()->StopServer(true);
723 CLog::Log(LOGNOTICE, "ES: Stopping event server");
725 CEventServer::GetInstance()->StopServer(bWait);
729 #endif // HAS_EVENT_SERVER
733 bool CNetworkServices::RefreshEventServer()
735 #ifdef HAS_EVENT_SERVER
736 if (!CSettings::Get().GetBool("services.esenabled"))
739 if (!IsEventServerRunning())
742 CEventServer::GetInstance()->RefreshSettings();
744 #endif // HAS_EVENT_SERVER
748 bool CNetworkServices::StartUPnP()
752 ret |= StartUPnPClient();
753 ret |= StartUPnPServer();
754 ret |= StartUPnPRenderer();
759 bool CNetworkServices::StopUPnP(bool bWait)
762 if (!CUPnP::IsInstantiated())
765 CLog::Log(LOGNOTICE, "stopping upnp");
766 CUPnP::ReleaseInstance(bWait);
773 bool CNetworkServices::StartUPnPClient()
776 if (!CSettings::Get().GetBool("services.upnpcontroller") ||
777 !CSettings::Get().GetBool("services.upnpserver"))
780 CLog::Log(LOGNOTICE, "starting upnp controller");
781 CUPnP::GetInstance()->StartClient();
782 return IsUPnPClientRunning();
787 bool CNetworkServices::IsUPnPClientRunning()
790 return CUPnP::GetInstance()->IsClientStarted();
795 bool CNetworkServices::StopUPnPClient()
798 if (!IsUPnPRendererRunning())
801 CLog::Log(LOGNOTICE, "stopping upnp client");
802 CUPnP::GetInstance()->StopClient();
809 bool CNetworkServices::StartUPnPRenderer()
812 if (!CSettings::Get().GetBool("services.upnprenderer"))
815 CLog::Log(LOGNOTICE, "starting upnp renderer");
816 return CUPnP::GetInstance()->StartRenderer();
821 bool CNetworkServices::IsUPnPRendererRunning()
824 return CUPnP::GetInstance()->IsInstantiated();
829 bool CNetworkServices::StopUPnPRenderer()
832 if (!IsUPnPRendererRunning())
835 CLog::Log(LOGNOTICE, "stopping upnp renderer");
836 CUPnP::GetInstance()->StopRenderer();
843 bool CNetworkServices::StartUPnPServer()
846 if (!CSettings::Get().GetBool("services.upnpserver"))
849 CLog::Log(LOGNOTICE, "starting upnp server");
850 return CUPnP::GetInstance()->StartServer();
855 bool CNetworkServices::IsUPnPServerRunning()
858 return CUPnP::GetInstance()->IsInstantiated();
863 bool CNetworkServices::StopUPnPServer()
866 if (!IsUPnPRendererRunning())
871 CLog::Log(LOGNOTICE, "stopping upnp server");
872 CUPnP::GetInstance()->StopServer();
879 bool CNetworkServices::StartRss()
884 CRssManager::Get().Start();
888 bool CNetworkServices::IsRssRunning()
890 return CRssManager::Get().IsActive();
893 bool CNetworkServices::StopRss()
898 CRssManager::Get().Stop();
902 bool CNetworkServices::StartZeroconf()
905 if (!CSettings::Get().GetBool("services.zeroconf"))
908 if (IsZeroconfRunning())
911 CLog::Log(LOGNOTICE, "starting zeroconf publishing");
912 return CZeroconf::GetInstance()->Start();
913 #endif // HAS_ZEROCONF
917 bool CNetworkServices::IsZeroconfRunning()
920 return CZeroconf::GetInstance()->IsStarted();
921 #endif // HAS_ZEROCONF
925 bool CNetworkServices::StopZeroconf()
928 if (!IsZeroconfRunning())
931 CLog::Log(LOGNOTICE, "stopping zeroconf publishing");
932 CZeroconf::GetInstance()->Stop();
935 #endif // HAS_ZEROCONF
939 bool CNetworkServices::ValidatePort(int port)
941 if (port <= 0 || port > 65535)
945 if (!CUtil::CanBindPrivileged() && (port < 1024 || port > 65535))