Line data Source code
1 : /*
2 : * If not stated otherwise in this file or this component's LICENSE file the
3 : * following copyright and licenses apply:
4 : *
5 : * Copyright 2022 Sky UK
6 : *
7 : * Licensed under the Apache License, Version 2.0 (the "License");
8 : * you may not use this file except in compliance with the License.
9 : * You may obtain a copy of the License at
10 : *
11 : * http://www.apache.org/licenses/LICENSE-2.0
12 : *
13 : * Unless required by applicable law or agreed to in writing, software
14 : * distributed under the License is distributed on an "AS IS" BASIS,
15 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 : * See the License for the specific language governing permissions and
17 : * limitations under the License.
18 : */
19 :
20 : #include "SessionServerManager.h"
21 : #include "IApplicationManagementServer.h"
22 : #include "IIpcFactory.h"
23 : #include "ISessionManagementServer.h"
24 : #include "RialtoServerLogging.h"
25 :
26 : #include <algorithm>
27 : #include <stdexcept>
28 : #include <utility>
29 :
30 : namespace
31 : {
32 5 : inline bool isNumber(const std::string &text)
33 : {
34 10 : return std::find_if(text.begin(), text.end(), [](const auto &letter) { return !std::isdigit(letter); }) == text.end();
35 : }
36 : } // namespace
37 :
38 : namespace firebolt::rialto::server::service
39 : {
40 26 : SessionServerManager::SessionServerManager(const ipc::IIpcFactory &ipcFactory, IPlaybackService &playbackService,
41 : ICdmService &cdmService, IControlService &controlService,
42 26 : std::unique_ptr<IHeartbeatProcedureFactory> &&heartbeatProcedureFactory)
43 26 : : m_playbackService{playbackService}, m_cdmService{cdmService}, m_controlService{controlService},
44 26 : m_heartbeatProcedureFactory{std::move(heartbeatProcedureFactory)},
45 26 : m_applicationManagementServer{ipcFactory.createApplicationManagementServer(*this)},
46 26 : m_sessionManagementServer{ipcFactory.createSessionManagementServer(playbackService, cdmService, controlService)},
47 52 : m_isServiceRunning{true}, m_currentState{common::SessionServerState::UNINITIALIZED}
48 : {
49 26 : RIALTO_SERVER_LOG_INFO("Starting Rialto Server Service");
50 : }
51 :
52 52 : SessionServerManager::~SessionServerManager()
53 : {
54 26 : RIALTO_SERVER_LOG_INFO("Stopping Rialto Server Service");
55 :
56 : // The following reset() will ensure that the thread ApplicationManagementServer::m_ipcServerThread
57 : // isn't currently calling any methods within this class (while it is being destructed)
58 : // Particularly, the mentioned thread is responsible for calling the method
59 : // SessionServerManager::switchToNotRunning() which then triggers a call to this destuctor
60 : // after it calls stopService()
61 26 : m_applicationManagementServer.reset();
62 :
63 26 : stopService();
64 52 : }
65 :
66 7 : bool SessionServerManager::initialize(int argc, char *argv[])
67 : try
68 : {
69 7 : if (argc != 2)
70 : {
71 2 : RIALTO_SERVER_LOG_ERROR("Wrong number of arguments. Rialto Server Service will close now.");
72 2 : return false;
73 : }
74 5 : std::string socketStr{argv[1]};
75 5 : if (!isNumber(socketStr))
76 : {
77 1 : RIALTO_SERVER_LOG_ERROR("Rialto App Management socket is not a number.");
78 1 : return false;
79 : }
80 4 : if (!m_applicationManagementServer->initialize(std::stoi(socketStr)))
81 : {
82 1 : RIALTO_SERVER_LOG_ERROR("Initialization of Application Management server failed.");
83 1 : return false;
84 : }
85 2 : m_applicationManagementServer->start();
86 2 : return m_applicationManagementServer->sendStateChangedEvent(common::SessionServerState::UNINITIALIZED);
87 5 : }
88 1 : catch (const std::exception &e)
89 : {
90 1 : RIALTO_SERVER_LOG_ERROR("Exception caught during service initialization: %s", e.what());
91 1 : return false;
92 : }
93 :
94 1 : void SessionServerManager::startService()
95 : {
96 1 : std::unique_lock<std::mutex> lock{m_serviceMutex};
97 3 : m_serviceCv.wait(lock, [this]() { return !m_isServiceRunning; });
98 1 : }
99 :
100 30 : void SessionServerManager::stopService()
101 : {
102 30 : std::unique_lock<std::mutex> lock{m_serviceMutex};
103 30 : if (m_isServiceRunning)
104 : {
105 26 : m_isServiceRunning = false;
106 26 : m_serviceCv.notify_one();
107 : }
108 30 : }
109 :
110 3 : bool SessionServerManager::setConfiguration(const std::string &socketName, const common::SessionServerState &state,
111 : const common::MaxResourceCapabilitites &maxResource,
112 : const std::string &clientDisplayName, unsigned int socketPermissions,
113 : const std::string &socketOwner, const std::string &socketGroup,
114 : const std::string &appName)
115 : {
116 3 : if (!m_sessionManagementServer->initialize(socketName, socketPermissions, socketOwner, socketGroup))
117 : {
118 1 : RIALTO_SERVER_LOG_ERROR("SetConfiguration failed - SessionManagementServer failed to initialize");
119 1 : return false;
120 : }
121 2 : m_sessionManagementServer->start();
122 2 : m_playbackService.setMaxPlaybacks(maxResource.maxPlaybacks);
123 2 : m_playbackService.setMaxWebAudioPlayers(maxResource.maxWebAudioPlayers);
124 2 : m_playbackService.setClientDisplayName(clientDisplayName);
125 2 : m_playbackService.setResourceManagerAppName(appName);
126 2 : return setState(state);
127 : }
128 :
129 21 : bool SessionServerManager::setState(const common::SessionServerState &state)
130 : {
131 21 : switch (state)
132 : {
133 7 : case common::SessionServerState::ACTIVE:
134 : {
135 7 : return switchToActive();
136 : }
137 7 : case common::SessionServerState::INACTIVE:
138 : {
139 7 : return switchToInactive();
140 : }
141 5 : case common::SessionServerState::NOT_RUNNING:
142 : {
143 5 : return switchToNotRunning();
144 : }
145 2 : default:
146 : {
147 2 : RIALTO_SERVER_LOG_ERROR("SetState failed - unsupported state");
148 2 : m_applicationManagementServer->sendStateChangedEvent(common::SessionServerState::ERROR);
149 : }
150 : }
151 2 : return false;
152 : }
153 :
154 1 : void SessionServerManager::setLogLevels(RIALTO_DEBUG_LEVEL defaultLogLevels, RIALTO_DEBUG_LEVEL clientLogLevels,
155 : RIALTO_DEBUG_LEVEL sessionServerLogLevels, RIALTO_DEBUG_LEVEL ipcLogLevels,
156 : RIALTO_DEBUG_LEVEL serverManagerLogLevels, RIALTO_DEBUG_LEVEL commonLogLevels)
157 : {
158 1 : firebolt::rialto::logging::setLogLevels(RIALTO_COMPONENT_DEFAULT, defaultLogLevels);
159 1 : firebolt::rialto::logging::setLogLevels(RIALTO_COMPONENT_CLIENT, clientLogLevels);
160 1 : firebolt::rialto::logging::setLogLevels(RIALTO_COMPONENT_SERVER, sessionServerLogLevels);
161 1 : firebolt::rialto::logging::setLogLevels(RIALTO_COMPONENT_IPC, ipcLogLevels);
162 1 : firebolt::rialto::logging::setLogLevels(RIALTO_COMPONENT_SERVER_MANAGER, serverManagerLogLevels);
163 1 : firebolt::rialto::logging::setLogLevels(RIALTO_COMPONENT_COMMON, commonLogLevels);
164 1 : m_sessionManagementServer->setLogLevels(defaultLogLevels, clientLogLevels, ipcLogLevels, commonLogLevels);
165 : }
166 :
167 2 : bool SessionServerManager::ping(std::int32_t id, const std::shared_ptr<IAckSender> &ackSender)
168 : {
169 2 : auto heartbeatProcedure{m_heartbeatProcedureFactory->createHeartbeatProcedure(ackSender, id)};
170 :
171 : // Check all rialto server internal threads
172 2 : m_cdmService.ping(heartbeatProcedure);
173 2 : m_playbackService.ping(heartbeatProcedure);
174 :
175 : // Check all Rialto Clients
176 4 : return m_controlService.ping(heartbeatProcedure);
177 2 : }
178 :
179 7 : bool SessionServerManager::switchToActive()
180 : {
181 7 : if (m_currentState.load() == common::SessionServerState::ACTIVE)
182 : {
183 1 : RIALTO_SERVER_LOG_DEBUG("Session server already in Active state.");
184 1 : return true;
185 : }
186 6 : if (!m_playbackService.switchToActive())
187 : {
188 1 : RIALTO_SERVER_LOG_ERROR("Player service failed to switch to active state");
189 1 : return false;
190 : }
191 5 : if (!m_cdmService.switchToActive())
192 : {
193 1 : RIALTO_SERVER_LOG_ERROR("Cdm service failed to switch to active state");
194 1 : m_playbackService.switchToInactive();
195 1 : return false;
196 : }
197 4 : if (m_applicationManagementServer->sendStateChangedEvent(common::SessionServerState::ACTIVE))
198 : {
199 3 : m_controlService.setApplicationState(ApplicationState::RUNNING);
200 3 : m_currentState.store(common::SessionServerState::ACTIVE);
201 3 : return true;
202 : }
203 1 : m_playbackService.switchToInactive();
204 1 : m_cdmService.switchToInactive();
205 1 : return false;
206 : }
207 :
208 7 : bool SessionServerManager::switchToInactive()
209 : {
210 7 : if (m_currentState.load() == common::SessionServerState::INACTIVE)
211 : {
212 1 : RIALTO_SERVER_LOG_DEBUG("Session server already in Inactive state.");
213 1 : return true;
214 : }
215 6 : m_playbackService.switchToInactive();
216 6 : m_cdmService.switchToInactive();
217 6 : if (m_applicationManagementServer->sendStateChangedEvent(common::SessionServerState::INACTIVE))
218 : {
219 3 : m_controlService.setApplicationState(ApplicationState::INACTIVE);
220 3 : m_currentState.store(common::SessionServerState::INACTIVE);
221 3 : return true;
222 : }
223 3 : if (m_currentState.load() == common::SessionServerState::ACTIVE)
224 : {
225 1 : if (!m_playbackService.switchToActive())
226 : {
227 1 : RIALTO_SERVER_LOG_WARN("Player service failed to switch to active state");
228 : }
229 1 : if (!m_cdmService.switchToActive())
230 : {
231 1 : RIALTO_SERVER_LOG_WARN("Cdm service failed to switch to active state");
232 : }
233 : }
234 3 : return false;
235 : }
236 :
237 5 : bool SessionServerManager::switchToNotRunning()
238 : {
239 5 : if (m_currentState.load() == common::SessionServerState::NOT_RUNNING)
240 : {
241 1 : RIALTO_SERVER_LOG_DEBUG("Session server already in NotRunning state.");
242 1 : return true;
243 : }
244 : // Free resources before sending notification to ServerManager
245 4 : m_playbackService.switchToInactive();
246 4 : m_cdmService.switchToInactive();
247 4 : m_controlService.setApplicationState(ApplicationState::UNKNOWN);
248 :
249 4 : bool result{true};
250 4 : if (m_applicationManagementServer->sendStateChangedEvent(common::SessionServerState::NOT_RUNNING))
251 : {
252 3 : m_currentState.store(common::SessionServerState::NOT_RUNNING);
253 : }
254 : else
255 : {
256 1 : result = false;
257 : }
258 :
259 : // stopService() needs to be the last command of this method.
260 : // It triggers destruction of SessionServerManager and therefore
261 : // some member variables may not be valid after this command
262 4 : stopService(); // This HAS TO BE LAST (see above)
263 4 : return result;
264 : }
265 : } // namespace firebolt::rialto::server::service
|