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 "Client.h"
21 : #include "CapabilityConverters.h"
22 : #include "IIpcChannel.h"
23 : #include "ISessionServerAppManager.h"
24 : #include "IpcLoop.h"
25 : #include "RialtoServerManagerLogging.h"
26 : #include "Utils.h"
27 : #include "servermanagermodule.pb.h"
28 : #include <cstring>
29 : #include <sys/socket.h>
30 : #include <sys/wait.h>
31 : #include <unistd.h>
32 :
33 : using firebolt::rialto::ipc::common::serialiseAudioCapabilities;
34 : using firebolt::rialto::ipc::common::serialiseVideoCapabilities;
35 :
36 : namespace
37 : {
38 1 : firebolt::rialto::common::SessionServerState convert(const rialto::SessionServerState &sessionServerState)
39 : {
40 1 : switch (sessionServerState)
41 : {
42 0 : case rialto::SessionServerState::UNINITIALIZED:
43 : {
44 0 : return firebolt::rialto::common::SessionServerState::UNINITIALIZED;
45 : }
46 1 : case rialto::SessionServerState::INACTIVE:
47 : {
48 1 : return firebolt::rialto::common::SessionServerState::INACTIVE;
49 : }
50 0 : case rialto::SessionServerState::ACTIVE:
51 : {
52 0 : return firebolt::rialto::common::SessionServerState::ACTIVE;
53 : }
54 0 : case rialto::SessionServerState::NOT_RUNNING:
55 : {
56 0 : return firebolt::rialto::common::SessionServerState::NOT_RUNNING;
57 : }
58 0 : case rialto::SessionServerState::ERROR:
59 : {
60 0 : return firebolt::rialto::common::SessionServerState::ERROR;
61 : }
62 0 : case rialto::SessionServerState::SUSPENDED:
63 : {
64 0 : return firebolt::rialto::common::SessionServerState::SUSPENDED;
65 : }
66 : }
67 0 : return firebolt::rialto::common::SessionServerState::ERROR;
68 : }
69 8 : rialto::SessionServerState convert(const firebolt::rialto::common::SessionServerState &state)
70 : {
71 8 : switch (state)
72 : {
73 0 : case firebolt::rialto::common::SessionServerState::UNINITIALIZED:
74 : {
75 0 : return rialto::SessionServerState::UNINITIALIZED;
76 : }
77 7 : case firebolt::rialto::common::SessionServerState::INACTIVE:
78 : {
79 7 : return rialto::SessionServerState::INACTIVE;
80 : }
81 0 : case firebolt::rialto::common::SessionServerState::ACTIVE:
82 : {
83 0 : return rialto::SessionServerState::ACTIVE;
84 : }
85 1 : case firebolt::rialto::common::SessionServerState::NOT_RUNNING:
86 : {
87 1 : return rialto::SessionServerState::NOT_RUNNING;
88 : }
89 0 : case firebolt::rialto::common::SessionServerState::ERROR:
90 : {
91 0 : return rialto::SessionServerState::ERROR;
92 : }
93 0 : case firebolt::rialto::common::SessionServerState::SUSPENDED:
94 : {
95 0 : return rialto::SessionServerState::SUSPENDED;
96 : }
97 : }
98 0 : return rialto::SessionServerState::ERROR;
99 : }
100 2 : rialto::LogLevels convert(const rialto::servermanager::service::LoggingLevels &levels)
101 : {
102 2 : rialto::LogLevels logLevels;
103 2 : if (rialto::servermanager::service::LoggingLevel::UNCHANGED != levels.defaultLoggingLevel)
104 : {
105 0 : logLevels.set_defaultloglevels(rialto::servermanager::common::convert(levels.defaultLoggingLevel));
106 : }
107 2 : if (rialto::servermanager::service::LoggingLevel::UNCHANGED != levels.clientLoggingLevel)
108 : {
109 0 : logLevels.set_clientloglevels(rialto::servermanager::common::convert(levels.clientLoggingLevel));
110 : }
111 2 : if (rialto::servermanager::service::LoggingLevel::UNCHANGED != levels.sessionServerLoggingLevel)
112 : {
113 0 : logLevels.set_sessionserverloglevels(rialto::servermanager::common::convert(levels.sessionServerLoggingLevel));
114 : }
115 2 : if (rialto::servermanager::service::LoggingLevel::UNCHANGED != levels.ipcLoggingLevel)
116 : {
117 0 : logLevels.set_ipcloglevels(rialto::servermanager::common::convert(levels.ipcLoggingLevel));
118 : }
119 2 : if (rialto::servermanager::service::LoggingLevel::UNCHANGED != levels.serverManagerLoggingLevel)
120 : {
121 0 : logLevels.set_servermanagerloglevels(rialto::servermanager::common::convert(levels.serverManagerLoggingLevel));
122 : }
123 2 : if (rialto::servermanager::service::LoggingLevel::UNCHANGED != levels.commonLoggingLevel)
124 : {
125 0 : logLevels.set_commonloglevels(rialto::servermanager::common::convert(levels.commonLoggingLevel));
126 : }
127 2 : return logLevels;
128 : }
129 4 : rialto::LogLevels getCurrentLogLevels()
130 : {
131 4 : rialto::LogLevels logLevels;
132 4 : logLevels.set_defaultloglevels(firebolt::rialto::logging::getLogLevels(RIALTO_COMPONENT_DEFAULT));
133 4 : logLevels.set_clientloglevels(firebolt::rialto::logging::getLogLevels(RIALTO_COMPONENT_CLIENT));
134 4 : logLevels.set_sessionserverloglevels(firebolt::rialto::logging::getLogLevels(RIALTO_COMPONENT_SERVER));
135 4 : logLevels.set_ipcloglevels(firebolt::rialto::logging::getLogLevels(RIALTO_COMPONENT_IPC));
136 4 : logLevels.set_servermanagerloglevels(firebolt::rialto::logging::getLogLevels(RIALTO_COMPONENT_SERVER_MANAGER));
137 4 : logLevels.set_commonloglevels(firebolt::rialto::logging::getLogLevels(RIALTO_COMPONENT_COMMON));
138 4 : return logLevels;
139 : }
140 : } // namespace
141 :
142 : namespace rialto::servermanager::ipc
143 : {
144 18 : Client::Client(std::unique_ptr<common::ISessionServerAppManager> &sessionServerAppManager, int serverId, int socket)
145 18 : : m_serverId{serverId}, m_sessionServerAppManager{sessionServerAppManager}, m_socket{socket}
146 : {
147 18 : RIALTO_SERVER_MANAGER_LOG_INFO("Constructing client for serverId: %d", m_serverId);
148 : }
149 :
150 18 : Client::~Client()
151 : {
152 18 : RIALTO_SERVER_MANAGER_LOG_INFO("Client for serverId: %d is destructed", m_serverId);
153 18 : m_isServerManagerShuttingDown = true;
154 18 : if (m_ipcLoop && m_ipcLoop->channel())
155 : {
156 51 : for (const auto &tag : m_eventTags)
157 : {
158 34 : m_ipcLoop->channel()->unsubscribe(tag);
159 : }
160 17 : m_eventTags.clear();
161 : }
162 18 : m_serviceStub.reset();
163 18 : m_ipcLoop.reset();
164 : }
165 :
166 18 : bool Client::connect()
167 : {
168 18 : m_ipcLoop = IpcLoop::create(m_socket, *this);
169 18 : if (!m_ipcLoop)
170 : {
171 1 : RIALTO_SERVER_MANAGER_LOG_ERROR("Failed to connect to rialto session server @ '%d'", m_socket);
172 1 : return false;
173 : }
174 17 : m_serviceStub = std::make_unique<::rialto::ServerManagerModule_Stub>(m_ipcLoop->channel());
175 34 : int eventTag{m_ipcLoop->channel()->subscribe<rialto::StateChangedEvent>(
176 34 : std::bind(&Client::onStateChangedEvent, this, std::placeholders::_1))};
177 17 : if (eventTag >= 0)
178 : {
179 17 : m_eventTags.push_back(eventTag);
180 : }
181 17 : eventTag =
182 17 : m_ipcLoop->channel()->subscribe<rialto::AckEvent>(std::bind(&Client::onAckEvent, this, std::placeholders::_1));
183 17 : if (eventTag >= 0)
184 : {
185 17 : m_eventTags.push_back(eventTag);
186 : }
187 17 : return true;
188 : }
189 :
190 4 : bool Client::performSetState(const firebolt::rialto::common::SessionServerState &state)
191 : {
192 4 : if (!m_ipcLoop || !m_serviceStub)
193 : {
194 0 : RIALTO_SERVER_MANAGER_LOG_ERROR("failed to set status - client is not active for serverId: %d", m_serverId);
195 0 : return false;
196 : }
197 4 : if (firebolt::rialto::common::SessionServerState::SUSPENDED == state ||
198 4 : firebolt::rialto::common::SessionServerState::NOT_RUNNING == state)
199 : {
200 1 : m_isServerShuttingDown = true;
201 : }
202 4 : rialto::SetStateRequest request;
203 4 : rialto::SetStateResponse response;
204 4 : request.set_sessionserverstate(convert(state));
205 4 : auto ipcController = m_ipcLoop->createRpcController();
206 4 : auto blockingClosure = m_ipcLoop->createBlockingClosure();
207 4 : m_serviceStub->setState(ipcController.get(), &request, &response, blockingClosure.get());
208 : // wait for the call to complete
209 4 : blockingClosure->wait();
210 :
211 : // check the result
212 4 : if (ipcController->Failed())
213 : {
214 1 : RIALTO_SERVER_MANAGER_LOG_ERROR("failed to set status due to '%s'", ipcController->ErrorText().c_str());
215 1 : return false;
216 : }
217 3 : return true;
218 4 : }
219 :
220 2 : bool Client::performSetConfiguration(const firebolt::rialto::common::SessionServerState &initialState,
221 : const std::string &socketName, const std::string &clientDisplayName,
222 : const firebolt::rialto::common::MaxResourceCapabilitites &maxResource,
223 : const unsigned int socketPermissions, const std::string &socketOwner,
224 : const std::string &socketGroup, const std::string &appName,
225 : const std::optional<firebolt::rialto::common::AudioDecoderCapabilities> &audioCaps,
226 : const std::optional<firebolt::rialto::common::VideoDecoderCapabilities> &videoCaps) const
227 : {
228 2 : if (!m_ipcLoop || !m_serviceStub)
229 : {
230 0 : RIALTO_SERVER_MANAGER_LOG_ERROR("failed to set configuration - client is not active for serverId: %d",
231 : m_serverId);
232 0 : return false;
233 : }
234 2 : rialto::SetConfigurationRequest request;
235 2 : rialto::SetConfigurationResponse response;
236 : request.set_sessionmanagementsocketname(socketName);
237 : request.set_clientdisplayname(clientDisplayName);
238 2 : request.mutable_resources()->set_maxplaybacks(maxResource.maxPlaybacks);
239 2 : request.mutable_resources()->set_maxwebaudioplayers(maxResource.maxWebAudioPlayers);
240 2 : request.set_socketpermissions(socketPermissions);
241 : request.set_socketowner(socketOwner);
242 : request.set_socketgroup(socketGroup);
243 : request.set_appname(appName);
244 2 : *(request.mutable_loglevels()) = getCurrentLogLevels();
245 2 : request.set_initialsessionserverstate(convert(initialState));
246 2 : if (audioCaps.has_value())
247 : {
248 0 : serialiseAudioCapabilities(*audioCaps, request.mutable_audiocapabilities());
249 0 : RIALTO_SERVER_MANAGER_LOG_DEBUG("Client: audio capabilities serialised into SetConfigurationRequest");
250 : }
251 2 : if (videoCaps.has_value())
252 : {
253 0 : serialiseVideoCapabilities(*videoCaps, request.mutable_videocapabilities());
254 0 : RIALTO_SERVER_MANAGER_LOG_DEBUG("Client: video capabilities serialised into SetConfigurationRequest");
255 : }
256 2 : if (!audioCaps.has_value() && !videoCaps.has_value())
257 : {
258 2 : RIALTO_SERVER_MANAGER_LOG_DEBUG(
259 : "Client: no capability data - SetConfigurationRequest sent without capabilities");
260 : }
261 2 : auto ipcController = m_ipcLoop->createRpcController();
262 2 : auto blockingClosure = m_ipcLoop->createBlockingClosure();
263 2 : m_serviceStub->setConfiguration(ipcController.get(), &request, &response, blockingClosure.get());
264 : // wait for the call to complete
265 2 : blockingClosure->wait();
266 :
267 : // check the result
268 2 : if (ipcController->Failed())
269 : {
270 1 : RIALTO_SERVER_MANAGER_LOG_ERROR("failed to set configuration due to '%s'", ipcController->ErrorText().c_str());
271 1 : return false;
272 : }
273 1 : return true;
274 2 : }
275 :
276 2 : bool Client::performSetConfiguration(const firebolt::rialto::common::SessionServerState &initialState, int socketFd,
277 : const std::string &clientDisplayName,
278 : const firebolt::rialto::common::MaxResourceCapabilitites &maxResource,
279 : const std::string &appName,
280 : const std::optional<firebolt::rialto::common::AudioDecoderCapabilities> &audioCaps,
281 : const std::optional<firebolt::rialto::common::VideoDecoderCapabilities> &videoCaps) const
282 : {
283 2 : if (!m_ipcLoop || !m_serviceStub)
284 : {
285 0 : RIALTO_SERVER_MANAGER_LOG_ERROR("failed to set configuration - client is not active for serverId: %d",
286 : m_serverId);
287 0 : return false;
288 : }
289 2 : rialto::SetConfigurationRequest request;
290 2 : rialto::SetConfigurationResponse response;
291 2 : request.set_sessionmanagementsocketfd(socketFd);
292 : request.set_clientdisplayname(clientDisplayName);
293 2 : request.mutable_resources()->set_maxplaybacks(maxResource.maxPlaybacks);
294 2 : request.mutable_resources()->set_maxwebaudioplayers(maxResource.maxWebAudioPlayers);
295 : request.set_appname(appName);
296 2 : *(request.mutable_loglevels()) = getCurrentLogLevels();
297 2 : request.set_initialsessionserverstate(convert(initialState));
298 2 : if (audioCaps.has_value())
299 : {
300 0 : serialiseAudioCapabilities(*audioCaps, request.mutable_audiocapabilities());
301 0 : RIALTO_SERVER_MANAGER_LOG_DEBUG("Client: audio capabilities serialised into SetConfigurationRequest");
302 : }
303 2 : if (videoCaps.has_value())
304 : {
305 0 : serialiseVideoCapabilities(*videoCaps, request.mutable_videocapabilities());
306 0 : RIALTO_SERVER_MANAGER_LOG_DEBUG("Client: video capabilities serialised into SetConfigurationRequest");
307 : }
308 2 : if (!audioCaps.has_value() && !videoCaps.has_value())
309 : {
310 2 : RIALTO_SERVER_MANAGER_LOG_DEBUG(
311 : "Client: no capability data - SetConfigurationRequest sent without capabilities");
312 : }
313 2 : auto ipcController = m_ipcLoop->createRpcController();
314 2 : auto blockingClosure = m_ipcLoop->createBlockingClosure();
315 2 : m_serviceStub->setConfiguration(ipcController.get(), &request, &response, blockingClosure.get());
316 : // wait for the call to complete
317 2 : blockingClosure->wait();
318 :
319 : // check the result
320 2 : if (ipcController->Failed())
321 : {
322 1 : RIALTO_SERVER_MANAGER_LOG_ERROR("failed to set configuration due to '%s'", ipcController->ErrorText().c_str());
323 1 : return false;
324 : }
325 1 : return true;
326 2 : }
327 :
328 2 : bool Client::performPing(int pingId) const
329 : {
330 2 : if (!m_ipcLoop || !m_serviceStub)
331 : {
332 0 : RIALTO_SERVER_MANAGER_LOG_ERROR("failed to ping - client is not active for serverId: %d", m_serverId);
333 0 : return false;
334 : }
335 2 : rialto::PingRequest request;
336 2 : rialto::PingResponse response;
337 2 : request.set_id(pingId);
338 2 : auto ipcController = m_ipcLoop->createRpcController();
339 2 : auto blockingClosure = m_ipcLoop->createBlockingClosure();
340 2 : m_serviceStub->ping(ipcController.get(), &request, &response, blockingClosure.get());
341 : // wait for the call to complete
342 2 : blockingClosure->wait();
343 :
344 : // check the result
345 2 : if (ipcController->Failed())
346 : {
347 1 : RIALTO_SERVER_MANAGER_LOG_ERROR("failed to ping due to '%s'", ipcController->ErrorText().c_str());
348 1 : return false;
349 : }
350 1 : return true;
351 2 : }
352 :
353 2 : bool Client::setLogLevels(const service::LoggingLevels &logLevels) const
354 : {
355 2 : if (!m_ipcLoop || !m_serviceStub)
356 : {
357 0 : RIALTO_SERVER_MANAGER_LOG_WARN("failed to change log levels - client is not active for serverId: %d", m_serverId);
358 0 : return false;
359 : }
360 2 : rialto::SetLogLevelsRequest request;
361 2 : rialto::SetLogLevelsResponse response;
362 2 : *(request.mutable_loglevels()) = convert(logLevels);
363 2 : auto ipcController = m_ipcLoop->createRpcController();
364 2 : auto blockingClosure = m_ipcLoop->createBlockingClosure();
365 2 : m_serviceStub->setLogLevels(ipcController.get(), &request, &response, blockingClosure.get());
366 : // wait for the call to complete
367 2 : blockingClosure->wait();
368 :
369 : // check the result
370 2 : if (ipcController->Failed())
371 : {
372 1 : RIALTO_SERVER_MANAGER_LOG_WARN("failed to change log levels due to '%s'", ipcController->ErrorText().c_str());
373 1 : return false;
374 : }
375 1 : return true;
376 2 : }
377 :
378 1 : void Client::onDisconnected() const
379 : {
380 1 : if (!m_sessionServerAppManager || m_isServerManagerShuttingDown || m_isServerShuttingDown)
381 : {
382 0 : RIALTO_SERVER_MANAGER_LOG_DEBUG("Connection to serverId: %d broken, but server is shutting down", m_serverId);
383 0 : return;
384 : }
385 1 : RIALTO_SERVER_MANAGER_LOG_WARN("Connection to serverId: %d broken, server probably crashed. Starting recovery",
386 : m_serverId);
387 1 : m_sessionServerAppManager->restartServer(m_serverId);
388 : }
389 :
390 1 : void Client::onStateChangedEvent(const std::shared_ptr<rialto::StateChangedEvent> &event) const
391 : {
392 1 : RIALTO_SERVER_MANAGER_LOG_DEBUG("StateChangedEvent received for serverId: %d", m_serverId);
393 1 : if (!m_sessionServerAppManager || !event || m_isServerManagerShuttingDown)
394 : {
395 0 : RIALTO_SERVER_MANAGER_LOG_WARN("Problem during StateChangedEvent processing");
396 0 : return;
397 : }
398 1 : m_sessionServerAppManager->onSessionServerStateChanged(m_serverId, convert(event->sessionserverstate()));
399 : }
400 :
401 1 : void Client::onAckEvent(const std::shared_ptr<rialto::AckEvent> &event) const
402 : {
403 1 : RIALTO_SERVER_MANAGER_LOG_DEBUG("AckEvent received for serverId: %d", m_serverId);
404 1 : if (!m_sessionServerAppManager || !event || m_isServerManagerShuttingDown)
405 : {
406 0 : RIALTO_SERVER_MANAGER_LOG_WARN("Problem during AckEvent processing");
407 0 : return;
408 : }
409 1 : m_sessionServerAppManager->onAck(m_serverId, event->id(), event->success());
410 : }
411 : } // namespace rialto::servermanager::ipc
|