LCOV - code coverage report
Current view: top level - serverManager/ipc/source - Client.cpp (source / functions) Coverage Total Hit
Test: coverage.info Lines: 77.9 % 190 148
Test Date: 2026-09-08 07:30:45 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            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
        

Generated by: LCOV version 2.0-1