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 4 : rialto::SessionServerState convert(const firebolt::rialto::common::SessionServerState &state)
62 : {
63 4 : switch (state)
64 : {
65 0 : case firebolt::rialto::common::SessionServerState::UNINITIALIZED:
66 : {
67 0 : return rialto::SessionServerState::UNINITIALIZED;
68 : }
69 4 : case firebolt::rialto::common::SessionServerState::INACTIVE:
70 : {
71 4 : 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 2 : rialto::LogLevels getCurrentLogLevels()
118 : {
119 2 : rialto::LogLevels logLevels;
120 2 : logLevels.set_defaultloglevels(firebolt::rialto::logging::getLogLevels(RIALTO_COMPONENT_DEFAULT));
121 2 : logLevels.set_clientloglevels(firebolt::rialto::logging::getLogLevels(RIALTO_COMPONENT_CLIENT));
122 2 : logLevels.set_sessionserverloglevels(firebolt::rialto::logging::getLogLevels(RIALTO_COMPONENT_SERVER));
123 2 : logLevels.set_ipcloglevels(firebolt::rialto::logging::getLogLevels(RIALTO_COMPONENT_IPC));
124 2 : logLevels.set_servermanagerloglevels(firebolt::rialto::logging::getLogLevels(RIALTO_COMPONENT_SERVER_MANAGER));
125 2 : logLevels.set_commonloglevels(firebolt::rialto::logging::getLogLevels(RIALTO_COMPONENT_COMMON));
126 2 : return logLevels;
127 : }
128 : } // namespace
129 :
130 : namespace rialto::servermanager::ipc
131 : {
132 15 : Client::Client(std::unique_ptr<common::ISessionServerAppManager> &sessionServerAppManager, int serverId, int socket)
133 15 : : m_serverId{serverId}, m_sessionServerAppManager{sessionServerAppManager}, m_socket{socket}
134 : {
135 15 : RIALTO_SERVER_MANAGER_LOG_INFO("Constructing client for serverId: %d", m_serverId);
136 : }
137 :
138 15 : Client::~Client()
139 : {
140 15 : RIALTO_SERVER_MANAGER_LOG_INFO("Client for serverId: %d is destructed", m_serverId);
141 15 : m_serviceStub.reset();
142 15 : m_ipcLoop.reset();
143 : }
144 :
145 15 : bool Client::connect()
146 : {
147 15 : m_ipcLoop = IpcLoop::create(m_socket, *this);
148 15 : if (!m_ipcLoop)
149 : {
150 1 : RIALTO_SERVER_MANAGER_LOG_ERROR("Failed to connect to rialto session server @ '%d'", m_socket);
151 1 : return false;
152 : }
153 14 : m_serviceStub = std::make_unique<::rialto::ServerManagerModule_Stub>(m_ipcLoop->channel());
154 28 : m_ipcLoop->channel()->subscribe<rialto::StateChangedEvent>(
155 14 : std::bind(&Client::onStateChangedEvent, this, std::placeholders::_1));
156 14 : m_ipcLoop->channel()->subscribe<rialto::AckEvent>(std::bind(&Client::onAckEvent, this, std::placeholders::_1));
157 14 : return true;
158 : }
159 :
160 2 : bool Client::performSetState(const firebolt::rialto::common::SessionServerState &state)
161 : {
162 2 : if (!m_ipcLoop || !m_serviceStub)
163 : {
164 0 : RIALTO_SERVER_MANAGER_LOG_ERROR("failed to set status - client is not active for serverId: %d", m_serverId);
165 0 : return false;
166 : }
167 2 : rialto::SetStateRequest request;
168 2 : rialto::SetStateResponse response;
169 2 : request.set_sessionserverstate(convert(state));
170 2 : auto ipcController = m_ipcLoop->createRpcController();
171 2 : auto blockingClosure = m_ipcLoop->createBlockingClosure();
172 2 : m_serviceStub->setState(ipcController.get(), &request, &response, blockingClosure.get());
173 : // wait for the call to complete
174 2 : blockingClosure->wait();
175 :
176 : // check the result
177 2 : if (ipcController->Failed())
178 : {
179 1 : RIALTO_SERVER_MANAGER_LOG_ERROR("failed to set status due to '%s'", ipcController->ErrorText().c_str());
180 1 : return false;
181 : }
182 1 : return true;
183 2 : }
184 :
185 2 : bool Client::performSetConfiguration(const firebolt::rialto::common::SessionServerState &initialState,
186 : const std::string &socketName, const std::string &clientDisplayName,
187 : const firebolt::rialto::common::MaxResourceCapabilitites &maxResource,
188 : const unsigned int socketPermissions, const std::string &socketOwner,
189 : const std::string &socketGroup, const std::string &appName) const
190 : {
191 2 : if (!m_ipcLoop || !m_serviceStub)
192 : {
193 0 : RIALTO_SERVER_MANAGER_LOG_ERROR("failed to set configuration - client is not active for serverId: %d",
194 : m_serverId);
195 0 : return false;
196 : }
197 2 : rialto::SetConfigurationRequest request;
198 2 : rialto::SetConfigurationResponse response;
199 2 : request.set_sessionmanagementsocketname(socketName);
200 2 : request.set_clientdisplayname(clientDisplayName);
201 2 : request.mutable_resources()->set_maxplaybacks(maxResource.maxPlaybacks);
202 2 : request.mutable_resources()->set_maxwebaudioplayers(maxResource.maxWebAudioPlayers);
203 2 : request.set_socketpermissions(socketPermissions);
204 2 : request.set_socketowner(socketOwner);
205 2 : request.set_socketgroup(socketGroup);
206 2 : request.set_appname(appName);
207 2 : *(request.mutable_loglevels()) = getCurrentLogLevels();
208 2 : request.set_initialsessionserverstate(convert(initialState));
209 2 : auto ipcController = m_ipcLoop->createRpcController();
210 2 : auto blockingClosure = m_ipcLoop->createBlockingClosure();
211 2 : m_serviceStub->setConfiguration(ipcController.get(), &request, &response, blockingClosure.get());
212 : // wait for the call to complete
213 2 : blockingClosure->wait();
214 :
215 : // check the result
216 2 : if (ipcController->Failed())
217 : {
218 1 : RIALTO_SERVER_MANAGER_LOG_ERROR("failed to set configuration due to '%s'", ipcController->ErrorText().c_str());
219 1 : return false;
220 : }
221 1 : return true;
222 2 : }
223 :
224 2 : bool Client::performPing(int pingId) const
225 : {
226 2 : if (!m_ipcLoop || !m_serviceStub)
227 : {
228 0 : RIALTO_SERVER_MANAGER_LOG_ERROR("failed to ping - client is not active for serverId: %d", m_serverId);
229 0 : return false;
230 : }
231 2 : rialto::PingRequest request;
232 2 : rialto::PingResponse response;
233 2 : request.set_id(pingId);
234 2 : auto ipcController = m_ipcLoop->createRpcController();
235 2 : auto blockingClosure = m_ipcLoop->createBlockingClosure();
236 2 : m_serviceStub->ping(ipcController.get(), &request, &response, blockingClosure.get());
237 : // wait for the call to complete
238 2 : blockingClosure->wait();
239 :
240 : // check the result
241 2 : if (ipcController->Failed())
242 : {
243 1 : RIALTO_SERVER_MANAGER_LOG_ERROR("failed to ping due to '%s'", ipcController->ErrorText().c_str());
244 1 : return false;
245 : }
246 1 : return true;
247 2 : }
248 :
249 2 : bool Client::setLogLevels(const service::LoggingLevels &logLevels) const
250 : {
251 2 : if (!m_ipcLoop || !m_serviceStub)
252 : {
253 0 : RIALTO_SERVER_MANAGER_LOG_WARN("failed to change log levels - client is not active for serverId: %d", m_serverId);
254 0 : return false;
255 : }
256 2 : rialto::SetLogLevelsRequest request;
257 2 : rialto::SetLogLevelsResponse response;
258 2 : *(request.mutable_loglevels()) = convert(logLevels);
259 2 : auto ipcController = m_ipcLoop->createRpcController();
260 2 : auto blockingClosure = m_ipcLoop->createBlockingClosure();
261 2 : m_serviceStub->setLogLevels(ipcController.get(), &request, &response, blockingClosure.get());
262 : // wait for the call to complete
263 2 : blockingClosure->wait();
264 :
265 : // check the result
266 2 : if (ipcController->Failed())
267 : {
268 1 : RIALTO_SERVER_MANAGER_LOG_WARN("failed to change log levels due to '%s'", ipcController->ErrorText().c_str());
269 1 : return false;
270 : }
271 1 : return true;
272 2 : }
273 :
274 1 : void Client::onDisconnected() const
275 : {
276 1 : RIALTO_SERVER_MANAGER_LOG_WARN("Connection to serverId: %d broken, server probably crashed. Starting recovery",
277 : m_serverId);
278 1 : m_sessionServerAppManager->restartServer(m_serverId);
279 : }
280 :
281 1 : void Client::onStateChangedEvent(const std::shared_ptr<rialto::StateChangedEvent> &event) const
282 : {
283 1 : RIALTO_SERVER_MANAGER_LOG_DEBUG("StateChangedEvent received for serverId: %d", m_serverId);
284 1 : if (!m_sessionServerAppManager || !event)
285 : {
286 0 : RIALTO_SERVER_MANAGER_LOG_WARN("Problem during StateChangedEvent processing");
287 0 : return;
288 : }
289 1 : m_sessionServerAppManager->onSessionServerStateChanged(m_serverId, convert(event->sessionserverstate()));
290 : }
291 :
292 1 : void Client::onAckEvent(const std::shared_ptr<rialto::AckEvent> &event) const
293 : {
294 1 : RIALTO_SERVER_MANAGER_LOG_DEBUG("AckEvent received for serverId: %d", m_serverId);
295 1 : if (!m_sessionServerAppManager || !event)
296 : {
297 0 : RIALTO_SERVER_MANAGER_LOG_WARN("Problem during AckEvent processing");
298 0 : return;
299 : }
300 1 : m_sessionServerAppManager->onAck(m_serverId, event->id(), event->success());
301 : }
302 : } // namespace rialto::servermanager::ipc
|