LCOV - code coverage report
Current view: top level - serverManager/ipc/source - Client.cpp (source / functions) Coverage Total Hit
Test: coverage.info Lines: 78.1 % 183 143
Test Date: 2026-02-13 09:21:56 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 "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
        

Generated by: LCOV version 2.0-1