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