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