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 "SessionManagementServer.h"
21 : #include "IControlModuleService.h"
22 : #include "IMediaKeysCapabilitiesModuleService.h"
23 : #include "IMediaKeysModuleService.h"
24 : #include "IMediaPipelineModuleService.h"
25 : #include "IWebAudioPlayerModuleService.h"
26 : #include "RialtoServerLogging.h"
27 : #include <IIpcServerFactory.h>
28 : #include <grp.h>
29 : #include <pwd.h>
30 : #include <sys/stat.h>
31 : #include <sys/types.h>
32 : #include <unistd.h>
33 :
34 : namespace
35 : {
36 : constexpr uid_t kNoOwnerChange = -1; // -1 means chown() won't change the owner
37 : constexpr gid_t kNoGroupChange = -1; // -1 means chown() won't change the group
38 : } // namespace
39 : namespace firebolt::rialto::server::ipc
40 : {
41 10 : SessionManagementServer::SessionManagementServer(
42 : std::weak_ptr<firebolt::rialto::wrappers::ILinuxWrapper> linuxWrapper,
43 : const std::shared_ptr<firebolt::rialto::ipc::IServerFactory> &ipcFactory,
44 : const std::shared_ptr<IMediaPipelineModuleServiceFactory> &mediaPipelineModuleFactory,
45 : const std::shared_ptr<IMediaPipelineCapabilitiesModuleServiceFactory> &mediaPipelineCapabilitiesModuleFactory,
46 : const std::shared_ptr<IMediaKeysModuleServiceFactory> &mediaKeysModuleFactory,
47 : const std::shared_ptr<IMediaKeysCapabilitiesModuleServiceFactory> &mediaKeysCapabilitiesModuleFactory,
48 : const std::shared_ptr<IWebAudioPlayerModuleServiceFactory> &webAudioPlayerModuleFactory,
49 : const std::shared_ptr<IControlModuleServiceFactory> &controlModuleFactory, service::IPlaybackService &playbackService,
50 10 : service::ICdmService &cdmService, service::IControlService &controlService)
51 20 : : m_isRunning{false}, m_mediaPipelineModule{mediaPipelineModuleFactory->create(
52 10 : playbackService.getMediaPipelineService())},
53 10 : m_mediaPipelineCapabilitiesModule{
54 10 : mediaPipelineCapabilitiesModuleFactory->create(playbackService.getMediaPipelineService())},
55 10 : m_mediaKeysModule{mediaKeysModuleFactory->create(cdmService)},
56 10 : m_mediaKeysCapabilitiesModule{mediaKeysCapabilitiesModuleFactory->create(cdmService)},
57 10 : m_webAudioPlayerModule{webAudioPlayerModuleFactory->create(playbackService.getWebAudioPlayerService())},
58 20 : m_controlModule{controlModuleFactory->create(playbackService, controlService)}, m_linuxWrapper{linuxWrapper.lock()}
59 : {
60 10 : m_ipcServer = ipcFactory->create();
61 : }
62 :
63 20 : SessionManagementServer::~SessionManagementServer()
64 : {
65 10 : stop();
66 10 : if (m_ipcServerThread.joinable())
67 : {
68 1 : m_ipcServerThread.join();
69 : }
70 20 : }
71 :
72 16 : size_t SessionManagementServer::getBufferSizeForPasswordStructureCalls() const
73 : {
74 : // Can return -1 on error
75 16 : return sysconf(_SC_GETPW_R_SIZE_MAX);
76 : }
77 :
78 8 : uid_t SessionManagementServer::getSocketOwnerId(const std::string &kSocketOwner) const
79 : {
80 8 : uid_t ownerId = kNoOwnerChange;
81 8 : const size_t kBufferSize = getBufferSizeForPasswordStructureCalls();
82 8 : if (!kSocketOwner.empty() && kBufferSize > 0)
83 : {
84 4 : errno = 0;
85 4 : passwd passwordStruct{};
86 4 : passwd *passwordResult = nullptr;
87 4 : char buffer[kBufferSize];
88 : int result =
89 4 : m_linuxWrapper->getpwnam_r(kSocketOwner.c_str(), &passwordStruct, buffer, kBufferSize, &passwordResult);
90 4 : if (result == 0 && passwordResult)
91 : {
92 2 : ownerId = passwordResult->pw_uid;
93 : }
94 : else
95 : {
96 2 : RIALTO_SERVER_LOG_SYS_WARN(errno, "Failed to determine ownerId for '%s'", kSocketOwner.c_str());
97 : }
98 4 : }
99 8 : return ownerId;
100 : }
101 :
102 8 : gid_t SessionManagementServer::getSocketGroupId(const std::string &kSocketGroup) const
103 : {
104 8 : gid_t groupId = kNoGroupChange;
105 8 : const size_t kBufferSize = getBufferSizeForPasswordStructureCalls();
106 8 : if (!kSocketGroup.empty() && kBufferSize > 0)
107 : {
108 4 : errno = 0;
109 4 : group groupStruct{};
110 4 : group *groupResult = nullptr;
111 4 : char buffer[kBufferSize];
112 4 : int result = m_linuxWrapper->getgrnam_r(kSocketGroup.c_str(), &groupStruct, buffer, kBufferSize, &groupResult);
113 4 : if (result == 0 && groupResult)
114 : {
115 2 : groupId = groupResult->gr_gid;
116 : }
117 : else
118 : {
119 2 : RIALTO_SERVER_LOG_SYS_WARN(errno, "Failed to determine groupId for '%s'", kSocketGroup.c_str());
120 : }
121 4 : }
122 8 : return groupId;
123 : }
124 :
125 9 : bool SessionManagementServer::initialize(const std::string &socketName, unsigned int socketPermissions,
126 : const std::string &socketOwner, const std::string &socketGroup)
127 : {
128 9 : RIALTO_SERVER_LOG_INFO("Initializing Session Management Server. Socket name: '%s'", socketName.c_str());
129 9 : if (!m_ipcServer)
130 : {
131 0 : RIALTO_SERVER_LOG_ERROR("Failed to initialize SessionManagementServer - Ipc server instance is NULL");
132 0 : return false;
133 : }
134 :
135 : // add a socket for clients and associate with a streamer object
136 27 : if (!m_ipcServer->addSocket(socketName,
137 18 : std::bind(&SessionManagementServer::onClientConnected, this, std::placeholders::_1),
138 18 : std::bind(&SessionManagementServer::onClientDisconnected, this, std::placeholders::_1)))
139 : {
140 1 : RIALTO_SERVER_LOG_ERROR("Failed to initialize SessionManagementServer - can't add socket '%s' to the ipc "
141 : "server",
142 : socketName.c_str());
143 1 : return false;
144 : }
145 :
146 8 : errno = 0;
147 8 : if (m_linuxWrapper->chmod(socketName.c_str(), socketPermissions) != 0)
148 : {
149 0 : RIALTO_SERVER_LOG_SYS_WARN(errno, "Failed to change the permissions on the IPC socket");
150 : }
151 :
152 8 : uid_t ownerId = getSocketOwnerId(socketOwner);
153 8 : gid_t groupId = getSocketGroupId(socketGroup);
154 :
155 8 : if (ownerId != kNoOwnerChange || groupId != kNoGroupChange)
156 : {
157 3 : errno = 0;
158 3 : if (m_linuxWrapper->chown(socketName.c_str(), ownerId, groupId) != 0)
159 : {
160 0 : RIALTO_SERVER_LOG_SYS_WARN(errno, "Failed to change the owner/group for the IPC socket");
161 : }
162 : }
163 :
164 8 : return true;
165 : }
166 :
167 1 : void SessionManagementServer::start()
168 : {
169 1 : if (m_isRunning.load())
170 : {
171 0 : RIALTO_SERVER_LOG_DEBUG("Server is already in running state");
172 0 : return;
173 : }
174 1 : RIALTO_SERVER_LOG_DEBUG("Starting Session Management Server event loop");
175 1 : m_isRunning.store(true);
176 2 : m_ipcServerThread = std::thread(
177 2 : [this]()
178 : {
179 1 : constexpr int kPollInterval{100};
180 1 : while (m_ipcServer->process() && m_isRunning.load())
181 : {
182 0 : m_ipcServer->wait(kPollInterval);
183 : }
184 1 : RIALTO_SERVER_LOG_MIL("Session Management Server event loop finished.");
185 1 : });
186 : }
187 :
188 10 : void SessionManagementServer::stop()
189 : {
190 10 : m_isRunning.store(false);
191 : }
192 :
193 1 : void SessionManagementServer::setLogLevels(RIALTO_DEBUG_LEVEL defaultLogLevels, RIALTO_DEBUG_LEVEL clientLogLevels,
194 : RIALTO_DEBUG_LEVEL ipcLogLevels, RIALTO_DEBUG_LEVEL commonLogLevels)
195 : {
196 1 : m_setLogLevelsService.setLogLevels(defaultLogLevels, clientLogLevels, ipcLogLevels, commonLogLevels);
197 : }
198 :
199 2 : void SessionManagementServer::onClientConnected(const std::shared_ptr<::firebolt::rialto::ipc::IClient> &client)
200 : {
201 2 : m_controlModule->clientConnected(client);
202 2 : m_mediaPipelineModule->clientConnected(client);
203 2 : m_mediaPipelineCapabilitiesModule->clientConnected(client);
204 2 : m_mediaKeysModule->clientConnected(client);
205 2 : m_mediaKeysCapabilitiesModule->clientConnected(client);
206 2 : m_webAudioPlayerModule->clientConnected(client);
207 2 : m_setLogLevelsService.clientConnected(client);
208 : }
209 :
210 1 : void SessionManagementServer::onClientDisconnected(const std::shared_ptr<::firebolt::rialto::ipc::IClient> &client)
211 : {
212 1 : m_setLogLevelsService.clientDisconnected(client);
213 1 : m_mediaKeysCapabilitiesModule->clientDisconnected(client);
214 1 : m_mediaKeysModule->clientDisconnected(client);
215 1 : m_mediaPipelineCapabilitiesModule->clientDisconnected(client);
216 1 : m_mediaPipelineModule->clientDisconnected(client);
217 1 : m_webAudioPlayerModule->clientDisconnected(client);
218 1 : m_controlModule->clientDisconnected(client);
219 : }
220 : } // namespace firebolt::rialto::server::ipc
|