LCOV - code coverage report
Current view: top level - serverManager/ipc/source - Client.cpp (source / functions) Coverage Total Hit
Test: coverage.info Lines: 75.7 % 206 156
Test Date: 2026-09-29 14:28:21 Functions: 100.0 % 15 15

            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
        

Generated by: LCOV version 2.0-1