1 /*
2  *  Copyright (C) 2005-2018 Team Kodi
3  *  This file is part of Kodi - https://kodi.tv
4  *
5  *  SPDX-License-Identifier: GPL-2.0-or-later
6  *  See LICENSES/README.md for more information.
7  */
8 
9 #include "NetworkServices.h"
10 
11 #include <utility>
12 
13 #include "ServiceBroker.h"
14 #include "dialogs/GUIDialogKaiToast.h"
15 #include "guilib/LocalizeStrings.h"
16 #include "interfaces/json-rpc/JSONRPC.h"
17 #include "messaging/ApplicationMessenger.h"
18 #include "messaging/helpers/DialogHelper.h"
19 #include "messaging/helpers/DialogOKHelper.h"
20 #include "network/EventServer.h"
21 #include "network/Network.h"
22 #include "network/TCPServer.h"
23 #include "settings/AdvancedSettings.h"
24 #include "settings/lib/Setting.h"
25 #include "settings/lib/SettingsManager.h"
26 #include "settings/Settings.h"
27 #include "settings/SettingsComponent.h"
28 #include "utils/log.h"
29 #include "utils/RssManager.h"
30 #include "utils/SystemInfo.h"
31 #include "utils/Variant.h"
32 
33 #ifdef TARGET_LINUX
34 #include "Util.h"
35 #endif
36 #ifdef HAS_AIRPLAY
37 #include "network/AirPlayServer.h"
38 #endif // HAS_AIRPLAY
39 
40 #ifdef HAS_AIRTUNES
41 #include "network/AirTunesServer.h"
42 #endif // HAS_AIRTUNES
43 
44 #ifdef HAS_ZEROCONF
45 #include "network/Zeroconf.h"
46 #endif // HAS_ZEROCONF
47 
48 #ifdef HAS_UPNP
49 #include "network/upnp/UPnP.h"
50 #endif // HAS_UPNP
51 
52 #ifdef HAS_WEB_SERVER
53 #include "network/WebServer.h"
54 #include "network/httprequesthandler/HTTPImageHandler.h"
55 #include "network/httprequesthandler/HTTPImageTransformationHandler.h"
56 #include "network/httprequesthandler/HTTPVfsHandler.h"
57 #include "network/httprequesthandler/HTTPJsonRpcHandler.h"
58 #ifdef HAS_WEB_INTERFACE
59 #ifdef HAS_PYTHON
60 #include "network/httprequesthandler/HTTPPythonHandler.h"
61 #endif
62 #include "network/httprequesthandler/HTTPWebinterfaceHandler.h"
63 #include "network/httprequesthandler/HTTPWebinterfaceAddonsHandler.h"
64 #endif // HAS_WEB_INTERFACE
65 #endif // HAS_WEB_SERVER
66 
67 #if defined(TARGET_DARWIN_OSX)
68 #include "platform/darwin/osx/XBMCHelper.h"
69 #endif
70 
71 using namespace KODI::MESSAGING;
72 using namespace JSONRPC;
73 using namespace EVENTSERVER;
74 #ifdef HAS_UPNP
75 using namespace UPNP;
76 #endif // HAS_UPNP
77 
78 using KODI::MESSAGING::HELPERS::DialogResponse;
79 
CNetworkServices()80 CNetworkServices::CNetworkServices()
81 #ifdef HAS_WEB_SERVER
82   : m_webserver(*new CWebServer),
83   m_httpImageHandler(*new CHTTPImageHandler),
84   m_httpImageTransformationHandler(*new CHTTPImageTransformationHandler),
85   m_httpVfsHandler(*new CHTTPVfsHandler),
86   m_httpJsonRpcHandler(*new CHTTPJsonRpcHandler)
87 #ifdef HAS_WEB_INTERFACE
88 #ifdef HAS_PYTHON
89   , m_httpPythonHandler(*new CHTTPPythonHandler)
90 #endif
91   , m_httpWebinterfaceHandler(*new CHTTPWebinterfaceHandler)
92   , m_httpWebinterfaceAddonsHandler(*new CHTTPWebinterfaceAddonsHandler)
93 #endif // HAS_WEB_INTERFACE
94 #endif // HAS_WEB_SERVER
95 {
96 #ifdef HAS_WEB_SERVER
97   m_webserver.RegisterRequestHandler(&m_httpImageHandler);
98   m_webserver.RegisterRequestHandler(&m_httpImageTransformationHandler);
99   m_webserver.RegisterRequestHandler(&m_httpVfsHandler);
100   m_webserver.RegisterRequestHandler(&m_httpJsonRpcHandler);
101 #ifdef HAS_WEB_INTERFACE
102 #ifdef HAS_PYTHON
103   m_webserver.RegisterRequestHandler(&m_httpPythonHandler);
104 #endif
105   m_webserver.RegisterRequestHandler(&m_httpWebinterfaceAddonsHandler);
106   m_webserver.RegisterRequestHandler(&m_httpWebinterfaceHandler);
107 #endif // HAS_WEB_INTERFACE
108 #endif // HAS_WEB_SERVER
109   std::set<std::string> settingSet{
110     CSettings::SETTING_SERVICES_WEBSERVER,
111     CSettings::SETTING_SERVICES_WEBSERVERPORT,
112     CSettings::SETTING_SERVICES_WEBSERVERAUTHENTICATION,
113     CSettings::SETTING_SERVICES_WEBSERVERUSERNAME,
114     CSettings::SETTING_SERVICES_WEBSERVERPASSWORD,
115     CSettings::SETTING_SERVICES_WEBSERVERSSL,
116     CSettings::SETTING_SERVICES_ZEROCONF,
117     CSettings::SETTING_SERVICES_AIRPLAY,
118     CSettings::SETTING_SERVICES_AIRPLAYVOLUMECONTROL,
119     CSettings::SETTING_SERVICES_AIRPLAYVIDEOSUPPORT,
120     CSettings::SETTING_SERVICES_USEAIRPLAYPASSWORD,
121     CSettings::SETTING_SERVICES_AIRPLAYPASSWORD,
122     CSettings::SETTING_SERVICES_UPNP,
123     CSettings::SETTING_SERVICES_UPNPSERVER,
124     CSettings::SETTING_SERVICES_UPNPRENDERER,
125     CSettings::SETTING_SERVICES_UPNPCONTROLLER,
126     CSettings::SETTING_SERVICES_ESENABLED,
127     CSettings::SETTING_SERVICES_ESPORT,
128     CSettings::SETTING_SERVICES_ESALLINTERFACES,
129     CSettings::SETTING_SERVICES_ESINITIALDELAY,
130     CSettings::SETTING_SERVICES_ESCONTINUOUSDELAY,
131     CSettings::SETTING_SMB_WINSSERVER,
132     CSettings::SETTING_SMB_WORKGROUP,
133     CSettings::SETTING_SMB_MINPROTOCOL,
134     CSettings::SETTING_SMB_MAXPROTOCOL,
135     CSettings::SETTING_SMB_LEGACYSECURITY
136   };
137   m_settings = CServiceBroker::GetSettingsComponent()->GetSettings();
138   m_settings->GetSettingsManager()->RegisterCallback(this, settingSet);
139 }
140 
~CNetworkServices()141 CNetworkServices::~CNetworkServices()
142 {
143   m_settings->GetSettingsManager()->UnregisterCallback(this);
144 #ifdef HAS_WEB_SERVER
145   m_webserver.UnregisterRequestHandler(&m_httpImageHandler);
146   delete &m_httpImageHandler;
147   m_webserver.UnregisterRequestHandler(&m_httpImageTransformationHandler);
148   delete &m_httpImageTransformationHandler;
149   m_webserver.UnregisterRequestHandler(&m_httpVfsHandler);
150   delete &m_httpVfsHandler;
151   m_webserver.UnregisterRequestHandler(&m_httpJsonRpcHandler);
152   delete &m_httpJsonRpcHandler;
153   CJSONRPC::Cleanup();
154 #ifdef HAS_WEB_INTERFACE
155 #ifdef HAS_PYTHON
156   m_webserver.UnregisterRequestHandler(&m_httpPythonHandler);
157   delete &m_httpPythonHandler;
158 #endif
159   m_webserver.UnregisterRequestHandler(&m_httpWebinterfaceAddonsHandler);
160   delete &m_httpWebinterfaceAddonsHandler;
161   m_webserver.UnregisterRequestHandler(&m_httpWebinterfaceHandler);
162   delete &m_httpWebinterfaceHandler;
163 #endif // HAS_WEB_INTERFACE
164   delete &m_webserver;
165 #endif // HAS_WEB_SERVER
166 }
167 
OnSettingChanging(const std::shared_ptr<const CSetting> & setting)168 bool CNetworkServices::OnSettingChanging(const std::shared_ptr<const CSetting>& setting)
169 {
170   if (setting == NULL)
171     return false;
172 
173   const std::string &settingId = setting->GetId();
174 #ifdef HAS_WEB_SERVER
175   // Ask user to confirm disabling the authentication requirement, but not when the configuration
176   // would be invalid when authentication was enabled (meaning that the change was triggered
177   // automatically)
178   if (settingId == CSettings::SETTING_SERVICES_WEBSERVERAUTHENTICATION &&
179       !std::static_pointer_cast<const CSettingBool>(setting)->GetValue() &&
180       (!m_settings->GetBool(CSettings::SETTING_SERVICES_WEBSERVER) ||
181        (m_settings->GetBool(CSettings::SETTING_SERVICES_WEBSERVER) &&
182         !m_settings->GetString(CSettings::SETTING_SERVICES_WEBSERVERPASSWORD).empty())) &&
183       HELPERS::ShowYesNoDialogText(19098, 36634) != DialogResponse::YES)
184   {
185     // Leave it as-is
186     return false;
187   }
188 
189   if (settingId == CSettings::SETTING_SERVICES_WEBSERVER ||
190       settingId == CSettings::SETTING_SERVICES_WEBSERVERPORT ||
191       settingId == CSettings::SETTING_SERVICES_WEBSERVERSSL ||
192       settingId == CSettings::SETTING_SERVICES_WEBSERVERAUTHENTICATION ||
193       settingId == CSettings::SETTING_SERVICES_WEBSERVERUSERNAME ||
194       settingId == CSettings::SETTING_SERVICES_WEBSERVERPASSWORD)
195   {
196     if (IsWebserverRunning() && !StopWebserver())
197       return false;
198 
199     if (m_settings->GetBool(CSettings::SETTING_SERVICES_WEBSERVER))
200     {
201       // Prevent changing to an invalid configuration
202       if ((settingId == CSettings::SETTING_SERVICES_WEBSERVER ||
203            settingId == CSettings::SETTING_SERVICES_WEBSERVERAUTHENTICATION ||
204            settingId == CSettings::SETTING_SERVICES_WEBSERVERPASSWORD) &&
205           m_settings->GetBool(CSettings::SETTING_SERVICES_WEBSERVERAUTHENTICATION) &&
206           m_settings->GetString(CSettings::SETTING_SERVICES_WEBSERVERPASSWORD).empty())
207       {
208         if (settingId == CSettings::SETTING_SERVICES_WEBSERVERAUTHENTICATION)
209         {
210           HELPERS::ShowOKDialogText(CVariant{257}, CVariant{36636});
211         }
212         else
213         {
214           HELPERS::ShowOKDialogText(CVariant{257}, CVariant{36635});
215         }
216         return false;
217       }
218 
219       // Ask for confirmation when enabling the web server
220       if (settingId == CSettings::SETTING_SERVICES_WEBSERVER &&
221           HELPERS::ShowYesNoDialogText(19098, 36632) != DialogResponse::YES)
222       {
223         // Revert change, do not start server
224         return false;
225       }
226 
227       if (!StartWebserver())
228       {
229         HELPERS::ShowOKDialogText(CVariant{33101}, CVariant{33100});
230         return false;
231       }
232     }
233   }
234   else if (settingId == CSettings::SETTING_SERVICES_ESPORT ||
235            settingId == CSettings::SETTING_SERVICES_WEBSERVERPORT)
236     return ValidatePort(std::static_pointer_cast<const CSettingInt>(setting)->GetValue());
237   else
238 #endif // HAS_WEB_SERVER
239 
240 #ifdef HAS_ZEROCONF
241   if (settingId == CSettings::SETTING_SERVICES_ZEROCONF)
242   {
243     if (std::static_pointer_cast<const CSettingBool>(setting)->GetValue())
244       return StartZeroconf();
245 #ifdef HAS_AIRPLAY
246     else
247     {
248       // cannot disable
249       if (IsAirPlayServerRunning() || IsAirTunesServerRunning())
250       {
251         HELPERS::ShowOKDialogText(CVariant{1259}, CVariant{34303});
252         return false;
253       }
254 
255       return StopZeroconf();
256     }
257 #endif // HAS_AIRPLAY
258   }
259   else
260 #endif // HAS_ZEROCONF
261 
262 #ifdef HAS_AIRPLAY
263   if (settingId == CSettings::SETTING_SERVICES_AIRPLAY)
264   {
265     if (std::static_pointer_cast<const CSettingBool>(setting)->GetValue())
266     {
267 #ifdef HAS_ZEROCONF
268       // AirPlay needs zeroconf
269       if (!m_settings->GetBool(CSettings::SETTING_SERVICES_ZEROCONF))
270       {
271         HELPERS::ShowOKDialogText(CVariant{1273}, CVariant{34302});
272         return false;
273       }
274 #endif //HAS_ZEROCONF
275 
276       // note - airtunesserver has to start before airplay server (ios7 client detection bug)
277 #ifdef HAS_AIRTUNES
278       if (!StartAirTunesServer())
279       {
280         HELPERS::ShowOKDialogText(CVariant{1274}, CVariant{33100});
281         return false;
282       }
283 #endif //HAS_AIRTUNES
284 
285       if (!StartAirPlayServer())
286       {
287         HELPERS::ShowOKDialogText(CVariant{1273}, CVariant{33100});
288         return false;
289       }
290     }
291     else
292     {
293       bool ret = true;
294 #ifdef HAS_AIRTUNES
295       if (!StopAirTunesServer(true))
296         ret = false;
297 #endif //HAS_AIRTUNES
298 
299       if (!StopAirPlayServer(true))
300         ret = false;
301 
302       if (!ret)
303         return false;
304     }
305   }
306   else if (settingId == CSettings::SETTING_SERVICES_AIRPLAYVIDEOSUPPORT)
307   {
308     if (std::static_pointer_cast<const CSettingBool>(setting)->GetValue())
309     {
310       if (!StartAirPlayServer())
311       {
312         HELPERS::ShowOKDialogText(CVariant{1273}, CVariant{33100});
313         return false;
314       }
315     }
316     else
317     {
318       if (!StopAirPlayServer(true))
319         return false;
320     }
321   }
322   else if (settingId == CSettings::SETTING_SERVICES_AIRPLAYPASSWORD ||
323            settingId == CSettings::SETTING_SERVICES_USEAIRPLAYPASSWORD)
324   {
325     if (!m_settings->GetBool(CSettings::SETTING_SERVICES_AIRPLAY))
326       return false;
327 
328     if (!CAirPlayServer::SetCredentials(m_settings->GetBool(CSettings::SETTING_SERVICES_USEAIRPLAYPASSWORD),
329                                         m_settings->GetString(CSettings::SETTING_SERVICES_AIRPLAYPASSWORD)))
330       return false;
331   }
332   else
333 #endif //HAS_AIRPLAY
334 
335 #ifdef HAS_UPNP
336   if (settingId == CSettings::SETTING_SERVICES_UPNP)
337   {
338     if (std::static_pointer_cast<const CSettingBool>(setting)->GetValue())
339     {
340       StartUPnPClient();
341       StartUPnPController();
342       StartUPnPServer();
343       StartUPnPRenderer();
344     }
345     else
346     {
347       StopUPnPRenderer();
348       StopUPnPServer();
349       StopUPnPController();
350       StopUPnPClient();
351     }
352   }
353   else if (settingId == CSettings::SETTING_SERVICES_UPNPSERVER)
354   {
355     if (std::static_pointer_cast<const CSettingBool>(setting)->GetValue())
356     {
357       if (!StartUPnPServer())
358         return false;
359 
360       // always stop and restart the client and controller if necessary
361       StopUPnPClient();
362       StopUPnPController();
363       StartUPnPClient();
364       StartUPnPController();
365     }
366     else
367       return StopUPnPServer();
368   }
369   else if (settingId == CSettings::SETTING_SERVICES_UPNPRENDERER)
370   {
371     if (std::static_pointer_cast<const CSettingBool>(setting)->GetValue())
372       return StartUPnPRenderer();
373     else
374       return StopUPnPRenderer();
375   }
376   else if (settingId == CSettings::SETTING_SERVICES_UPNPCONTROLLER)
377   {
378     // always stop and restart
379     StopUPnPController();
380     if (std::static_pointer_cast<const CSettingBool>(setting)->GetValue())
381       return StartUPnPController();
382   }
383   else
384 #endif // HAS_UPNP
385 
386   if (settingId == CSettings::SETTING_SERVICES_ESENABLED)
387   {
388     if (std::static_pointer_cast<const CSettingBool>(setting)->GetValue())
389     {
390       bool result = true;
391       if (!StartEventServer())
392       {
393         HELPERS::ShowOKDialogText(CVariant{33102}, CVariant{33100});
394         result = false;
395       }
396 
397       if (!StartJSONRPCServer())
398       {
399         HELPERS::ShowOKDialogText(CVariant{33103}, CVariant{33100});
400         result = false;
401       }
402       return result;
403     }
404     else
405     {
406       bool result = true;
407       result = StopEventServer(true, true);
408       result &= StopJSONRPCServer(false);
409       return result;
410     }
411   }
412   else if (settingId == CSettings::SETTING_SERVICES_ESPORT)
413   {
414     // restart eventserver without asking user
415     if (!StopEventServer(true, false))
416       return false;
417 
418     if (!StartEventServer())
419     {
420       HELPERS::ShowOKDialogText(CVariant{33102}, CVariant{33100});
421       return false;
422     }
423 
424 #if defined(TARGET_DARWIN_OSX)
425     // reconfigure XBMCHelper for port changes
426     XBMCHelper::GetInstance().Configure();
427 #endif // TARGET_DARWIN_OSX
428   }
429   else if (settingId == CSettings::SETTING_SERVICES_ESALLINTERFACES)
430   {
431     if (m_settings->GetBool(CSettings::SETTING_SERVICES_ESALLINTERFACES) &&
432         HELPERS::ShowYesNoDialogText(19098, 36633) != DialogResponse::YES)
433     {
434       // Revert change, do not start server
435       return false;
436     }
437 
438     if (m_settings->GetBool(CSettings::SETTING_SERVICES_ESENABLED))
439     {
440       if (!StopEventServer(true, true))
441         return false;
442 
443       if (!StartEventServer())
444       {
445         HELPERS::ShowOKDialogText(CVariant{33102}, CVariant{33100});
446         return false;
447       }
448     }
449 
450     if (m_settings->GetBool(CSettings::SETTING_SERVICES_ESENABLED))
451     {
452       if (!StopJSONRPCServer(true))
453         return false;
454 
455       if (!StartJSONRPCServer())
456       {
457         HELPERS::ShowOKDialogText(CVariant{33103}, CVariant{33100});
458         return false;
459       }
460     }
461   }
462 
463   else if (settingId == CSettings::SETTING_SERVICES_ESINITIALDELAY ||
464            settingId == CSettings::SETTING_SERVICES_ESCONTINUOUSDELAY)
465   {
466     if (m_settings->GetBool(CSettings::SETTING_SERVICES_ESENABLED))
467       return RefreshEventServer();
468   }
469 
470   return true;
471 }
472 
OnSettingChanged(const std::shared_ptr<const CSetting> & setting)473 void CNetworkServices::OnSettingChanged(const std::shared_ptr<const CSetting>& setting)
474 {
475   if (setting == NULL)
476     return;
477 
478   const std::string& settingId = setting->GetId();
479   if (settingId == CSettings::SETTING_SMB_WINSSERVER ||
480       settingId == CSettings::SETTING_SMB_WORKGROUP ||
481       settingId == CSettings::SETTING_SMB_MINPROTOCOL ||
482       settingId == CSettings::SETTING_SMB_MAXPROTOCOL ||
483       settingId == CSettings::SETTING_SMB_LEGACYSECURITY)
484   {
485     // okey we really don't need to restart, only deinit samba, but that could be damn hard if something is playing
486     //! @todo - General way of handling setting changes that require restart
487     if (HELPERS::ShowYesNoDialogText(CVariant{14038}, CVariant{14039}) == DialogResponse::YES)
488     {
489       m_settings->Save();
490       CApplicationMessenger::GetInstance().PostMsg(TMSG_RESTARTAPP);
491     }
492   }
493 }
494 
OnSettingUpdate(const std::shared_ptr<CSetting> & setting,const char * oldSettingId,const TiXmlNode * oldSettingNode)495 bool CNetworkServices::OnSettingUpdate(const std::shared_ptr<CSetting>& setting,
496                                        const char* oldSettingId,
497                                        const TiXmlNode* oldSettingNode)
498 {
499   if (setting == NULL)
500     return false;
501 
502   const std::string &settingId = setting->GetId();
503   if (settingId == CSettings::SETTING_SERVICES_WEBSERVERUSERNAME)
504   {
505     // if webserverusername is xbmc and pw is not empty we treat it as altered
506     // and don't change the username to kodi - part of rebrand
507     if (m_settings->GetString(CSettings::SETTING_SERVICES_WEBSERVERUSERNAME) == "xbmc" &&
508         !m_settings->GetString(CSettings::SETTING_SERVICES_WEBSERVERPASSWORD).empty())
509       return true;
510   }
511   if (settingId == CSettings::SETTING_SERVICES_WEBSERVERPORT)
512   {
513     // if webserverport is default but webserver is activated then treat it as altered
514     // and don't change the port to new value
515     if (m_settings->GetBool(CSettings::SETTING_SERVICES_WEBSERVER))
516       return true;
517   }
518   return false;
519 }
520 
Start()521 void CNetworkServices::Start()
522 {
523   StartZeroconf();
524   if (m_settings->GetBool(CSettings::SETTING_SERVICES_UPNP))
525     StartUPnP();
526   if (m_settings->GetBool(CSettings::SETTING_SERVICES_ESENABLED) && !StartEventServer())
527     CGUIDialogKaiToast::QueueNotification(CGUIDialogKaiToast::Warning, g_localizeStrings.Get(33102), g_localizeStrings.Get(33100));
528   if (m_settings->GetBool(CSettings::SETTING_SERVICES_ESENABLED) && !StartJSONRPCServer())
529     CGUIDialogKaiToast::QueueNotification(CGUIDialogKaiToast::Warning, g_localizeStrings.Get(33103), g_localizeStrings.Get(33100));
530 
531 #ifdef HAS_WEB_SERVER
532   // Start web server after eventserver and JSON-RPC server, so users can use these interfaces
533   // to confirm the warning message below if it is shown
534   if (m_settings->GetBool(CSettings::SETTING_SERVICES_WEBSERVER))
535   {
536     // services.webserverauthentication setting was added in Kodi v18 and requires a valid password
537     // to be set, but on upgrade the setting will be activated automatically regardless of whether
538     // a password was set before -> this can lead to an invalid configuration
539     if (m_settings->GetBool(CSettings::SETTING_SERVICES_WEBSERVERAUTHENTICATION) &&
540         m_settings->GetString(CSettings::SETTING_SERVICES_WEBSERVERPASSWORD).empty())
541     {
542       // Alert user to new default security settings in new Kodi version
543       HELPERS::ShowOKDialogText(33101, 33104);
544       // Fix settings: Disable web server
545       m_settings->SetBool(CSettings::SETTING_SERVICES_WEBSERVER, false);
546       // Bring user to settings screen where authentication can be configured properly
547       CServiceBroker::GetGUI()->GetWindowManager().ActivateWindow(
548           WINDOW_SETTINGS_SERVICE, std::vector<std::string>{"services.webserverauthentication"});
549     }
550     // Only try to start server if configuration is OK
551     else if (!StartWebserver())
552       CGUIDialogKaiToast::QueueNotification(
553           CGUIDialogKaiToast::Warning, g_localizeStrings.Get(33101), g_localizeStrings.Get(33100));
554   }
555 #endif // HAS_WEB_SERVER
556 
557   // note - airtunesserver has to start before airplay server (ios7 client detection bug)
558   StartAirTunesServer();
559   StartAirPlayServer();
560   StartRss();
561 }
562 
Stop(bool bWait)563 void CNetworkServices::Stop(bool bWait)
564 {
565   if (bWait)
566   {
567     StopUPnP(bWait);
568     StopZeroconf();
569     StopWebserver();
570     StopRss();
571   }
572 
573   StopEventServer(bWait, false);
574   StopJSONRPCServer(bWait);
575   StopAirPlayServer(bWait);
576   StopAirTunesServer(bWait);
577 }
578 
StartWebserver()579 bool CNetworkServices::StartWebserver()
580 {
581 #ifdef HAS_WEB_SERVER
582   if (!CServiceBroker::GetNetwork().IsAvailable())
583     return false;
584 
585   if (!m_settings->GetBool(CSettings::SETTING_SERVICES_WEBSERVER))
586     return false;
587 
588   if (m_settings->GetBool(CSettings::SETTING_SERVICES_WEBSERVERAUTHENTICATION) &&
589       m_settings->GetString(CSettings::SETTING_SERVICES_WEBSERVERPASSWORD).empty())
590   {
591     CLog::Log(LOGERROR, "Tried to start webserver with invalid configuration (authentication "
592                         "enabled, but no password set");
593     return false;
594   }
595 
596   int webPort = m_settings->GetInt(CSettings::SETTING_SERVICES_WEBSERVERPORT);
597   if (!ValidatePort(webPort))
598   {
599     CLog::Log(LOGERROR, "Cannot start Web Server on port %i", webPort);
600     return false;
601   }
602 
603   if (IsWebserverRunning())
604     return true;
605 
606   std::string username;
607   std::string password;
608   if (m_settings->GetBool(CSettings::SETTING_SERVICES_WEBSERVERAUTHENTICATION))
609   {
610     username = m_settings->GetString(CSettings::SETTING_SERVICES_WEBSERVERUSERNAME);
611     password = m_settings->GetString(CSettings::SETTING_SERVICES_WEBSERVERPASSWORD);
612   }
613 
614   if (!m_webserver.Start(webPort, username, password))
615     return false;
616 
617 #ifdef HAS_ZEROCONF
618   std::vector<std::pair<std::string, std::string> > txt;
619   txt.emplace_back("txtvers", "1");
620   txt.emplace_back("uuid", CServiceBroker::GetSettingsComponent()->GetSettings()->GetString(
621                              CSettings::SETTING_SERVICES_DEVICEUUID));
622 
623   // publish web frontend and API services
624 #ifdef HAS_WEB_INTERFACE
625   CZeroconf::GetInstance()->PublishService("servers.webserver", "_http._tcp", CSysInfo::GetDeviceName(), webPort, txt);
626 #endif // HAS_WEB_INTERFACE
627   CZeroconf::GetInstance()->PublishService("servers.jsonrpc-http", "_xbmc-jsonrpc-h._tcp", CSysInfo::GetDeviceName(), webPort, txt);
628 #endif // HAS_ZEROCONF
629 
630   return true;
631 #endif // HAS_WEB_SERVER
632   return false;
633 }
634 
IsWebserverRunning()635 bool CNetworkServices::IsWebserverRunning()
636 {
637 #ifdef HAS_WEB_SERVER
638   return m_webserver.IsStarted();
639 #endif // HAS_WEB_SERVER
640   return false;
641 }
642 
StopWebserver()643 bool CNetworkServices::StopWebserver()
644 {
645 #ifdef HAS_WEB_SERVER
646   if (!IsWebserverRunning())
647     return true;
648 
649   if (!m_webserver.Stop() || m_webserver.IsStarted())
650   {
651     CLog::Log(LOGWARNING, "Webserver: Failed to stop.");
652     return false;
653   }
654 
655 #ifdef HAS_ZEROCONF
656 #ifdef HAS_WEB_INTERFACE
657   CZeroconf::GetInstance()->RemoveService("servers.webserver");
658 #endif // HAS_WEB_INTERFACE
659   CZeroconf::GetInstance()->RemoveService("servers.jsonrpc-http");
660 #endif // HAS_ZEROCONF
661 
662   return true;
663 #endif // HAS_WEB_SERVER
664   return false;
665 }
666 
StartAirPlayServer()667 bool CNetworkServices::StartAirPlayServer()
668 {
669   if (!m_settings->GetBool(CSettings::SETTING_SERVICES_AIRPLAYVIDEOSUPPORT))
670     return true;
671 
672 #ifdef HAS_AIRPLAY
673   if (!CServiceBroker::GetNetwork().IsAvailable() || !m_settings->GetBool(CSettings::SETTING_SERVICES_AIRPLAY))
674     return false;
675 
676   if (IsAirPlayServerRunning())
677     return true;
678 
679   if (!CAirPlayServer::StartServer(CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_airPlayPort, true))
680     return false;
681 
682   if (!CAirPlayServer::SetCredentials(m_settings->GetBool(CSettings::SETTING_SERVICES_USEAIRPLAYPASSWORD),
683                                       m_settings->GetString(CSettings::SETTING_SERVICES_AIRPLAYPASSWORD)))
684     return false;
685 
686 #ifdef HAS_ZEROCONF
687   std::vector<std::pair<std::string, std::string> > txt;
688   CNetworkInterface* iface = CServiceBroker::GetNetwork().GetFirstConnectedInterface();
689   txt.emplace_back("deviceid", iface != nullptr ? iface->GetMacAddress() : "FF:FF:FF:FF:FF:F2");
690   txt.emplace_back("model", "Xbmc,1");
691   txt.emplace_back("srcvers", AIRPLAY_SERVER_VERSION_STR);
692 
693   // for ios8 clients we need to announce mirroring support
694   // else we won't get video urls anymore.
695   // We also announce photo caching support (as it seems faster and
696   // we have implemented it anyways).
697   txt.emplace_back("features", "0x20F7");
698 
699   CZeroconf::GetInstance()->PublishService("servers.airplay", "_airplay._tcp", CSysInfo::GetDeviceName(), CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_airPlayPort, txt);
700 #endif // HAS_ZEROCONF
701 
702   return true;
703 #endif // HAS_AIRPLAY
704   return false;
705 }
706 
IsAirPlayServerRunning()707 bool CNetworkServices::IsAirPlayServerRunning()
708 {
709 #ifdef HAS_AIRPLAY
710   return CAirPlayServer::IsRunning();
711 #endif // HAS_AIRPLAY
712   return false;
713 }
714 
StopAirPlayServer(bool bWait)715 bool CNetworkServices::StopAirPlayServer(bool bWait)
716 {
717 #ifdef HAS_AIRPLAY
718   if (!IsAirPlayServerRunning())
719     return true;
720 
721   CAirPlayServer::StopServer(bWait);
722 
723 #ifdef HAS_ZEROCONF
724   CZeroconf::GetInstance()->RemoveService("servers.airplay");
725 #endif // HAS_ZEROCONF
726 
727   return true;
728 #endif // HAS_AIRPLAY
729   return false;
730 }
731 
StartAirTunesServer()732 bool CNetworkServices::StartAirTunesServer()
733 {
734 #ifdef HAS_AIRTUNES
735   if (!CServiceBroker::GetNetwork().IsAvailable() || !m_settings->GetBool(CSettings::SETTING_SERVICES_AIRPLAY))
736     return false;
737 
738   if (IsAirTunesServerRunning())
739     return true;
740 
741   if (!CAirTunesServer::StartServer(CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_airTunesPort, true,
742                                     m_settings->GetBool(CSettings::SETTING_SERVICES_USEAIRPLAYPASSWORD),
743                                     m_settings->GetString(CSettings::SETTING_SERVICES_AIRPLAYPASSWORD)))
744   {
745     CLog::Log(LOGERROR, "Failed to start AirTunes Server");
746     return false;
747   }
748 
749   return true;
750 #endif // HAS_AIRTUNES
751   return false;
752 }
753 
IsAirTunesServerRunning()754 bool CNetworkServices::IsAirTunesServerRunning()
755 {
756 #ifdef HAS_AIRTUNES
757   return CAirTunesServer::IsRunning();
758 #endif // HAS_AIRTUNES
759   return false;
760 }
761 
StopAirTunesServer(bool bWait)762 bool CNetworkServices::StopAirTunesServer(bool bWait)
763 {
764 #ifdef HAS_AIRTUNES
765   if (!IsAirTunesServerRunning())
766     return true;
767 
768   CAirTunesServer::StopServer(bWait);
769   return true;
770 #endif // HAS_AIRTUNES
771   return false;
772 }
773 
StartJSONRPCServer()774 bool CNetworkServices::StartJSONRPCServer()
775 {
776   if (!m_settings->GetBool(CSettings::SETTING_SERVICES_ESENABLED))
777     return false;
778 
779   if (IsJSONRPCServerRunning())
780     return true;
781 
782   if (!CTCPServer::StartServer(CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_jsonTcpPort, m_settings->GetBool(CSettings::SETTING_SERVICES_ESALLINTERFACES)))
783     return false;
784 
785 #ifdef HAS_ZEROCONF
786   std::vector<std::pair<std::string, std::string> > txt;
787   txt.emplace_back("txtvers", "1");
788   txt.emplace_back("uuid", CServiceBroker::GetSettingsComponent()->GetSettings()->GetString(
789                              CSettings::SETTING_SERVICES_DEVICEUUID));
790 
791   CZeroconf::GetInstance()->PublishService("servers.jsonrpc-tpc", "_xbmc-jsonrpc._tcp", CSysInfo::GetDeviceName(), CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_jsonTcpPort, txt);
792 #endif // HAS_ZEROCONF
793 
794   return true;
795 }
796 
IsJSONRPCServerRunning()797 bool CNetworkServices::IsJSONRPCServerRunning()
798 {
799   return CTCPServer::IsRunning();
800 }
801 
StopJSONRPCServer(bool bWait)802 bool CNetworkServices::StopJSONRPCServer(bool bWait)
803 {
804   if (!IsJSONRPCServerRunning())
805     return true;
806 
807   CTCPServer::StopServer(bWait);
808 
809 #ifdef HAS_ZEROCONF
810   CZeroconf::GetInstance()->RemoveService("servers.jsonrpc-tcp");
811 #endif // HAS_ZEROCONF
812 
813   return true;
814 }
815 
StartEventServer()816 bool CNetworkServices::StartEventServer()
817 {
818   if (!m_settings->GetBool(CSettings::SETTING_SERVICES_ESENABLED))
819     return false;
820 
821   if (IsEventServerRunning())
822     return true;
823 
824   CEventServer* server = CEventServer::GetInstance();
825   if (!server)
826   {
827     CLog::Log(LOGERROR, "ES: Out of memory");
828     return false;
829   }
830 
831   server->StartServer();
832 
833   return true;
834 }
835 
IsEventServerRunning()836 bool CNetworkServices::IsEventServerRunning()
837 {
838   return CEventServer::GetInstance()->Running();
839 }
840 
StopEventServer(bool bWait,bool promptuser)841 bool CNetworkServices::StopEventServer(bool bWait, bool promptuser)
842 {
843   if (!IsEventServerRunning())
844     return true;
845 
846   CEventServer* server = CEventServer::GetInstance();
847   if (!server)
848   {
849     CLog::Log(LOGERROR, "ES: Out of memory");
850     return false;
851   }
852 
853   if (promptuser)
854   {
855     if (server->GetNumberOfClients() > 0)
856     {
857       if (HELPERS::ShowYesNoDialogText(CVariant{13140}, CVariant{13141}, CVariant{""}, CVariant{""}, 10000) !=
858         DialogResponse::YES)
859       {
860         CLog::Log(LOGINFO, "ES: Not stopping event server");
861         return false;
862       }
863     }
864     CLog::Log(LOGINFO, "ES: Stopping event server with confirmation");
865 
866     CEventServer::GetInstance()->StopServer(true);
867   }
868   else
869   {
870     if (!bWait)
871       CLog::Log(LOGINFO, "ES: Stopping event server");
872 
873     CEventServer::GetInstance()->StopServer(bWait);
874   }
875 
876   return true;
877 }
878 
RefreshEventServer()879 bool CNetworkServices::RefreshEventServer()
880 {
881   if (!m_settings->GetBool(CSettings::SETTING_SERVICES_ESENABLED))
882     return false;
883 
884   if (!IsEventServerRunning())
885     return false;
886 
887   CEventServer::GetInstance()->RefreshSettings();
888   return true;
889 }
890 
StartUPnP()891 bool CNetworkServices::StartUPnP()
892 {
893   bool ret = false;
894 #ifdef HAS_UPNP
895   ret |= StartUPnPClient();
896   if (m_settings->GetBool(CSettings::SETTING_SERVICES_UPNPSERVER))
897   {
898    ret |= StartUPnPServer();
899   }
900 
901   if (m_settings->GetBool(CSettings::SETTING_SERVICES_UPNPCONTROLLER))
902   {
903     ret |= StartUPnPController();
904   }
905 
906   if (m_settings->GetBool(CSettings::SETTING_SERVICES_UPNPRENDERER))
907   {
908     ret |= StartUPnPRenderer();
909   }
910 #endif // HAS_UPNP
911   return ret;
912 }
913 
StopUPnP(bool bWait)914 bool CNetworkServices::StopUPnP(bool bWait)
915 {
916 #ifdef HAS_UPNP
917   if (!CUPnP::IsInstantiated())
918     return true;
919 
920   CLog::Log(LOGINFO, "stopping upnp");
921   CUPnP::ReleaseInstance(bWait);
922 
923   return true;
924 #endif // HAS_UPNP
925   return false;
926 }
927 
StartUPnPClient()928 bool CNetworkServices::StartUPnPClient()
929 {
930 #ifdef HAS_UPNP
931   if (!m_settings->GetBool(CSettings::SETTING_SERVICES_UPNP))
932     return false;
933 
934   CLog::Log(LOGINFO, "starting upnp client");
935   CUPnP::GetInstance()->StartClient();
936   return IsUPnPClientRunning();
937 #endif // HAS_UPNP
938   return false;
939 }
940 
IsUPnPClientRunning()941 bool CNetworkServices::IsUPnPClientRunning()
942 {
943 #ifdef HAS_UPNP
944   return CUPnP::GetInstance()->IsClientStarted();
945 #endif // HAS_UPNP
946   return false;
947 }
948 
StopUPnPClient()949 bool CNetworkServices::StopUPnPClient()
950 {
951 #ifdef HAS_UPNP
952   if (!IsUPnPClientRunning())
953     return true;
954 
955   CLog::Log(LOGINFO, "stopping upnp client");
956   CUPnP::GetInstance()->StopClient();
957 
958   return true;
959 #endif // HAS_UPNP
960   return false;
961 }
962 
StartUPnPController()963 bool CNetworkServices::StartUPnPController()
964 {
965 #ifdef HAS_UPNP
966   if (!m_settings->GetBool(CSettings::SETTING_SERVICES_UPNPCONTROLLER) ||
967       !m_settings->GetBool(CSettings::SETTING_SERVICES_UPNPSERVER) ||
968       !m_settings->GetBool(CSettings::SETTING_SERVICES_UPNP))
969     return false;
970 
971   CLog::Log(LOGINFO, "starting upnp controller");
972   CUPnP::GetInstance()->StartController();
973   return IsUPnPControllerRunning();
974 #endif // HAS_UPNP
975   return false;
976 }
977 
IsUPnPControllerRunning()978 bool CNetworkServices::IsUPnPControllerRunning()
979 {
980 #ifdef HAS_UPNP
981   return CUPnP::GetInstance()->IsControllerStarted();
982 #endif // HAS_UPNP
983   return false;
984 }
985 
StopUPnPController()986 bool CNetworkServices::StopUPnPController()
987 {
988 #ifdef HAS_UPNP
989   if (!IsUPnPControllerRunning())
990     return true;
991 
992   CLog::Log(LOGINFO, "stopping upnp controller");
993   CUPnP::GetInstance()->StopController();
994 
995   return true;
996 #endif // HAS_UPNP
997   return false;
998 }
999 
StartUPnPRenderer()1000 bool CNetworkServices::StartUPnPRenderer()
1001 {
1002 #ifdef HAS_UPNP
1003   if (!m_settings->GetBool(CSettings::SETTING_SERVICES_UPNPRENDERER) ||
1004       !m_settings->GetBool(CSettings::SETTING_SERVICES_UPNP))
1005     return false;
1006 
1007   CLog::Log(LOGINFO, "starting upnp renderer");
1008   return CUPnP::GetInstance()->StartRenderer();
1009 #endif // HAS_UPNP
1010   return false;
1011 }
1012 
IsUPnPRendererRunning()1013 bool CNetworkServices::IsUPnPRendererRunning()
1014 {
1015 #ifdef HAS_UPNP
1016   return CUPnP::GetInstance()->IsInstantiated();
1017 #endif // HAS_UPNP
1018   return false;
1019 }
1020 
StopUPnPRenderer()1021 bool CNetworkServices::StopUPnPRenderer()
1022 {
1023 #ifdef HAS_UPNP
1024   if (!IsUPnPRendererRunning())
1025     return true;
1026 
1027   CLog::Log(LOGINFO, "stopping upnp renderer");
1028   CUPnP::GetInstance()->StopRenderer();
1029 
1030   return true;
1031 #endif // HAS_UPNP
1032   return false;
1033 }
1034 
StartUPnPServer()1035 bool CNetworkServices::StartUPnPServer()
1036 {
1037 #ifdef HAS_UPNP
1038   if (!m_settings->GetBool(CSettings::SETTING_SERVICES_UPNPSERVER) ||
1039       !m_settings->GetBool(CSettings::SETTING_SERVICES_UPNP))
1040     return false;
1041 
1042   CLog::Log(LOGINFO, "starting upnp server");
1043   return CUPnP::GetInstance()->StartServer();
1044 #endif // HAS_UPNP
1045   return false;
1046 }
1047 
IsUPnPServerRunning()1048 bool CNetworkServices::IsUPnPServerRunning()
1049 {
1050 #ifdef HAS_UPNP
1051   return CUPnP::GetInstance()->IsInstantiated();
1052 #endif // HAS_UPNP
1053   return false;
1054 }
1055 
StopUPnPServer()1056 bool CNetworkServices::StopUPnPServer()
1057 {
1058 #ifdef HAS_UPNP
1059   if (!IsUPnPServerRunning())
1060     return true;
1061 
1062   StopUPnPController();
1063 
1064   CLog::Log(LOGINFO, "stopping upnp server");
1065   CUPnP::GetInstance()->StopServer();
1066 
1067   return true;
1068 #endif // HAS_UPNP
1069   return false;
1070 }
1071 
StartRss()1072 bool CNetworkServices::StartRss()
1073 {
1074   if (IsRssRunning())
1075     return true;
1076 
1077   CRssManager::GetInstance().Start();
1078   return true;
1079 }
1080 
IsRssRunning()1081 bool CNetworkServices::IsRssRunning()
1082 {
1083   return CRssManager::GetInstance().IsActive();
1084 }
1085 
StopRss()1086 bool CNetworkServices::StopRss()
1087 {
1088   if (!IsRssRunning())
1089     return true;
1090 
1091   CRssManager::GetInstance().Stop();
1092   return true;
1093 }
1094 
StartZeroconf()1095 bool CNetworkServices::StartZeroconf()
1096 {
1097 #ifdef HAS_ZEROCONF
1098   if (!m_settings->GetBool(CSettings::SETTING_SERVICES_ZEROCONF))
1099     return false;
1100 
1101   if (IsZeroconfRunning())
1102     return true;
1103 
1104   CLog::Log(LOGINFO, "starting zeroconf publishing");
1105   return CZeroconf::GetInstance()->Start();
1106 #endif // HAS_ZEROCONF
1107   return false;
1108 }
1109 
IsZeroconfRunning()1110 bool CNetworkServices::IsZeroconfRunning()
1111 {
1112 #ifdef HAS_ZEROCONF
1113   return CZeroconf::GetInstance()->IsStarted();
1114 #endif // HAS_ZEROCONF
1115   return false;
1116 }
1117 
StopZeroconf()1118 bool CNetworkServices::StopZeroconf()
1119 {
1120 #ifdef HAS_ZEROCONF
1121   if (!IsZeroconfRunning())
1122     return true;
1123 
1124   CLog::Log(LOGINFO, "stopping zeroconf publishing");
1125   CZeroconf::GetInstance()->Stop();
1126 
1127   return true;
1128 #endif // HAS_ZEROCONF
1129   return false;
1130 }
1131 
ValidatePort(int port)1132 bool CNetworkServices::ValidatePort(int port)
1133 {
1134   if (port <= 0 || port > 65535)
1135     return false;
1136 
1137 #ifdef TARGET_LINUX
1138   if (!CUtil::CanBindPrivileged() && (port < 1024 || port > 65535))
1139     return false;
1140 #endif
1141 
1142   return true;
1143 }
1144