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