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 "MediaKeysModuleService.h"
21 : #include "ICdmService.h"
22 : #include "MediaKeysClient.h"
23 : #include "RialtoServerLogging.h"
24 : #include <IIpcController.h>
25 : #include <algorithm>
26 : #include <cstdint>
27 :
28 : namespace
29 : {
30 3 : int generateHandle()
31 : {
32 : static int mediaKeysHandle{0};
33 3 : return mediaKeysHandle++;
34 : }
35 :
36 : firebolt::rialto::ProtoMediaKeyErrorStatus
37 32 : convertMediaKeyErrorStatus(const firebolt::rialto::MediaKeyErrorStatus &errorStatus)
38 : {
39 32 : switch (errorStatus)
40 : {
41 16 : case firebolt::rialto::MediaKeyErrorStatus::OK:
42 : {
43 16 : return firebolt::rialto::ProtoMediaKeyErrorStatus::OK;
44 : }
45 0 : case firebolt::rialto::MediaKeyErrorStatus::BAD_SESSION_ID:
46 : {
47 0 : return firebolt::rialto::ProtoMediaKeyErrorStatus::BAD_SESSION_ID;
48 : }
49 0 : case firebolt::rialto::MediaKeyErrorStatus::NOT_SUPPORTED:
50 : {
51 0 : return firebolt::rialto::ProtoMediaKeyErrorStatus::NOT_SUPPORTED;
52 : }
53 16 : case firebolt::rialto::MediaKeyErrorStatus::INVALID_STATE:
54 : {
55 16 : return firebolt::rialto::ProtoMediaKeyErrorStatus::INVALID_STATE;
56 : }
57 0 : case firebolt::rialto::MediaKeyErrorStatus::FAIL:
58 : {
59 0 : return firebolt::rialto::ProtoMediaKeyErrorStatus::FAIL;
60 : }
61 : }
62 0 : return firebolt::rialto::ProtoMediaKeyErrorStatus::FAIL;
63 : }
64 : firebolt::rialto::KeySessionType
65 2 : convertKeySessionType(const firebolt::rialto::CreateKeySessionRequest_KeySessionType &protoKeySessionType)
66 : {
67 2 : switch (protoKeySessionType)
68 : {
69 2 : case firebolt::rialto::CreateKeySessionRequest_KeySessionType::CreateKeySessionRequest_KeySessionType_TEMPORARY:
70 2 : return firebolt::rialto::KeySessionType::TEMPORARY;
71 0 : case firebolt::rialto::CreateKeySessionRequest_KeySessionType::CreateKeySessionRequest_KeySessionType_PERSISTENT_LICENCE:
72 0 : return firebolt::rialto::KeySessionType::PERSISTENT_LICENCE;
73 0 : case firebolt::rialto::CreateKeySessionRequest_KeySessionType::CreateKeySessionRequest_KeySessionType_PERSISTENT_RELEASE_MESSAGE:
74 0 : return firebolt::rialto::KeySessionType::PERSISTENT_RELEASE_MESSAGE;
75 0 : default:
76 0 : return firebolt::rialto::KeySessionType::UNKNOWN;
77 : }
78 : }
79 2 : firebolt::rialto::InitDataType covertInitDataType(firebolt::rialto::GenerateRequestRequest_InitDataType protoInitDataType)
80 : {
81 2 : switch (protoInitDataType)
82 : {
83 2 : case firebolt::rialto::GenerateRequestRequest_InitDataType::GenerateRequestRequest_InitDataType_CENC:
84 2 : return firebolt::rialto::InitDataType::CENC;
85 0 : case firebolt::rialto::GenerateRequestRequest_InitDataType::GenerateRequestRequest_InitDataType_KEY_IDS:
86 0 : return firebolt::rialto::InitDataType::KEY_IDS;
87 0 : case firebolt::rialto::GenerateRequestRequest_InitDataType::GenerateRequestRequest_InitDataType_WEBM:
88 0 : return firebolt::rialto::InitDataType::WEBM;
89 0 : case firebolt::rialto::GenerateRequestRequest_InitDataType::GenerateRequestRequest_InitDataType_DRMHEADER:
90 0 : return firebolt::rialto::InitDataType::DRMHEADER;
91 0 : default:
92 0 : return firebolt::rialto::InitDataType::UNKNOWN;
93 : }
94 : }
95 : } // namespace
96 :
97 : namespace firebolt::rialto::server::ipc
98 : {
99 1 : std::shared_ptr<IMediaKeysModuleServiceFactory> IMediaKeysModuleServiceFactory::createFactory()
100 : {
101 1 : std::shared_ptr<IMediaKeysModuleServiceFactory> factory;
102 :
103 : try
104 : {
105 1 : factory = std::make_shared<MediaKeysModuleServiceFactory>();
106 : }
107 0 : catch (const std::exception &e)
108 : {
109 0 : RIALTO_SERVER_LOG_ERROR("Failed to create the media keys module service factory, reason: %s", e.what());
110 : }
111 :
112 1 : return factory;
113 : }
114 :
115 1 : std::shared_ptr<IMediaKeysModuleService> MediaKeysModuleServiceFactory::create(service::ICdmService &cdmService) const
116 : {
117 1 : std::shared_ptr<IMediaKeysModuleService> mediaKeysModule;
118 :
119 : try
120 : {
121 1 : mediaKeysModule = std::make_shared<MediaKeysModuleService>(cdmService);
122 : }
123 0 : catch (const std::exception &e)
124 : {
125 0 : RIALTO_SERVER_LOG_ERROR("Failed to create the media keys module service, reason: %s", e.what());
126 : }
127 :
128 1 : return mediaKeysModule;
129 : }
130 :
131 48 : MediaKeysModuleService::MediaKeysModuleService(service::ICdmService &cdmService) : m_cdmService{cdmService} {}
132 :
133 : MediaKeysModuleService::~MediaKeysModuleService() {}
134 :
135 2 : void MediaKeysModuleService::clientConnected(const std::shared_ptr<::firebolt::rialto::ipc::IClient> &ipcClient)
136 : {
137 2 : RIALTO_SERVER_LOG_INFO("Client Connected!");
138 : {
139 2 : m_clientMediaKeysHandles.emplace(ipcClient, std::set<int>());
140 : }
141 2 : ipcClient->exportService(shared_from_this());
142 : }
143 :
144 1 : void MediaKeysModuleService::clientDisconnected(const std::shared_ptr<::firebolt::rialto::ipc::IClient> &ipcClient)
145 : {
146 1 : RIALTO_SERVER_LOG_INFO("Client disconnected!");
147 1 : std::set<int> mediaKeysHandles;
148 : {
149 1 : auto handleIter = m_clientMediaKeysHandles.find(ipcClient);
150 1 : if (handleIter == m_clientMediaKeysHandles.end())
151 : {
152 0 : RIALTO_SERVER_LOG_ERROR("unknown client disconnected");
153 0 : return;
154 : }
155 1 : mediaKeysHandles = handleIter->second; // copy to avoid deadlock
156 1 : m_clientMediaKeysHandles.erase(handleIter);
157 : }
158 2 : for (const auto &mediaKeysHandle : mediaKeysHandles)
159 : {
160 1 : m_cdmService.destroyMediaKeys(mediaKeysHandle);
161 : }
162 : }
163 :
164 4 : void MediaKeysModuleService::createMediaKeys(::google::protobuf::RpcController *controller,
165 : const ::firebolt::rialto::CreateMediaKeysRequest *request,
166 : ::firebolt::rialto::CreateMediaKeysResponse *response,
167 : ::google::protobuf::Closure *done)
168 : {
169 4 : RIALTO_SERVER_LOG_DEBUG("entry:");
170 4 : auto ipcController = dynamic_cast<firebolt::rialto::ipc::IController *>(controller);
171 4 : if (!ipcController)
172 : {
173 1 : RIALTO_SERVER_LOG_ERROR("ipc library provided incompatible controller object");
174 1 : controller->SetFailed("ipc library provided incompatible controller object");
175 1 : done->Run();
176 1 : return;
177 : }
178 :
179 3 : int mediaKeysHandle = generateHandle();
180 3 : bool mediaKeysCreated = m_cdmService.createMediaKeys(mediaKeysHandle, request->key_system());
181 3 : if (mediaKeysCreated)
182 : {
183 : // Assume that IPC library works well and client is present
184 2 : m_clientMediaKeysHandles[ipcController->getClient()].insert(mediaKeysHandle);
185 2 : response->set_media_keys_handle(mediaKeysHandle);
186 : }
187 : else
188 : {
189 1 : RIALTO_SERVER_LOG_ERROR("Create media keys failed");
190 1 : controller->SetFailed("Operation failed");
191 : }
192 3 : done->Run();
193 : }
194 :
195 3 : void MediaKeysModuleService::destroyMediaKeys(::google::protobuf::RpcController *controller,
196 : const ::firebolt::rialto::DestroyMediaKeysRequest *request,
197 : ::firebolt::rialto::DestroyMediaKeysResponse *response,
198 : ::google::protobuf::Closure *done)
199 : {
200 3 : RIALTO_SERVER_LOG_DEBUG("entry:");
201 3 : auto ipcController = dynamic_cast<firebolt::rialto::ipc::IController *>(controller);
202 3 : if (!ipcController)
203 : {
204 1 : RIALTO_SERVER_LOG_ERROR("ipc library provided incompatible controller object");
205 1 : controller->SetFailed("ipc library provided incompatible controller object");
206 1 : done->Run();
207 2 : return;
208 : }
209 2 : if (!m_cdmService.destroyMediaKeys(request->media_keys_handle()))
210 : {
211 1 : RIALTO_SERVER_LOG_ERROR("Destroy session failed");
212 1 : controller->SetFailed("Operation failed");
213 1 : done->Run();
214 1 : return;
215 : }
216 1 : auto handleIter = m_clientMediaKeysHandles.find(ipcController->getClient());
217 1 : if (handleIter != m_clientMediaKeysHandles.end())
218 : {
219 0 : handleIter->second.erase(request->media_keys_handle());
220 : }
221 1 : done->Run();
222 : }
223 :
224 2 : void MediaKeysModuleService::containsKey(::google::protobuf::RpcController *controller,
225 : const ::firebolt::rialto::ContainsKeyRequest *request,
226 : ::firebolt::rialto::ContainsKeyResponse *response,
227 : ::google::protobuf::Closure *done)
228 : {
229 2 : RIALTO_SERVER_LOG_DEBUG("entry:");
230 :
231 2 : bool result = m_cdmService.containsKey(request->media_keys_handle(), request->key_session_id(),
232 4 : std::vector<std::uint8_t>{request->key_id().begin(), request->key_id().end()});
233 2 : response->set_contains_key(result);
234 2 : done->Run();
235 : }
236 :
237 3 : void MediaKeysModuleService::createKeySession(::google::protobuf::RpcController *controller,
238 : const ::firebolt::rialto::CreateKeySessionRequest *request,
239 : ::firebolt::rialto::CreateKeySessionResponse *response,
240 : ::google::protobuf::Closure *done)
241 : {
242 3 : RIALTO_SERVER_LOG_DEBUG("entry:");
243 3 : auto ipcController = dynamic_cast<firebolt::rialto::ipc::IController *>(controller);
244 3 : if (!ipcController)
245 : {
246 1 : RIALTO_SERVER_LOG_ERROR("ipc library provided incompatible controller object");
247 1 : controller->SetFailed("ipc library provided incompatible controller object");
248 1 : done->Run();
249 1 : return;
250 : }
251 :
252 : int32_t keySessionId;
253 : MediaKeyErrorStatus status =
254 2 : m_cdmService.createKeySession(request->media_keys_handle(), convertKeySessionType(request->session_type()),
255 4 : std::make_shared<MediaKeysClient>(request->media_keys_handle(),
256 2 : ipcController->getClient()),
257 4 : request->is_ldl(), keySessionId);
258 2 : if (MediaKeyErrorStatus::OK == status)
259 : {
260 1 : response->set_key_session_id(keySessionId);
261 : }
262 2 : response->set_error_status(convertMediaKeyErrorStatus(status));
263 2 : done->Run();
264 : }
265 :
266 2 : void MediaKeysModuleService::generateRequest(::google::protobuf::RpcController *controller,
267 : const ::firebolt::rialto::GenerateRequestRequest *request,
268 : ::firebolt::rialto::GenerateRequestResponse *response,
269 : ::google::protobuf::Closure *done)
270 : {
271 2 : RIALTO_SERVER_LOG_DEBUG("entry:");
272 :
273 2 : MediaKeyErrorStatus status = m_cdmService.generateRequest(request->media_keys_handle(), request->key_session_id(),
274 : covertInitDataType(request->init_data_type()),
275 6 : std::vector<std::uint8_t>{request->init_data().begin(),
276 4 : request->init_data().end()});
277 2 : response->set_error_status(convertMediaKeyErrorStatus(status));
278 2 : done->Run();
279 : }
280 :
281 2 : void MediaKeysModuleService::loadSession(::google::protobuf::RpcController *controller,
282 : const ::firebolt::rialto::LoadSessionRequest *request,
283 : ::firebolt::rialto::LoadSessionResponse *response,
284 : ::google::protobuf::Closure *done)
285 : {
286 2 : RIALTO_SERVER_LOG_DEBUG("entry:");
287 :
288 2 : MediaKeyErrorStatus status = m_cdmService.loadSession(request->media_keys_handle(), request->key_session_id());
289 2 : response->set_error_status(convertMediaKeyErrorStatus(status));
290 2 : done->Run();
291 : }
292 :
293 2 : void MediaKeysModuleService::updateSession(::google::protobuf::RpcController *controller,
294 : const ::firebolt::rialto::UpdateSessionRequest *request,
295 : ::firebolt::rialto::UpdateSessionResponse *response,
296 : ::google::protobuf::Closure *done)
297 : {
298 2 : RIALTO_SERVER_LOG_DEBUG("entry:");
299 :
300 2 : MediaKeyErrorStatus status = m_cdmService.updateSession(request->media_keys_handle(), request->key_session_id(),
301 6 : std::vector<std::uint8_t>{request->response_data().begin(),
302 4 : request->response_data().end()});
303 2 : response->set_error_status(convertMediaKeyErrorStatus(status));
304 2 : done->Run();
305 : }
306 :
307 2 : void MediaKeysModuleService::setDrmHeader(::google::protobuf::RpcController *controller,
308 : const ::firebolt::rialto::SetDrmHeaderRequest *request,
309 : ::firebolt::rialto::SetDrmHeaderResponse *response,
310 : ::google::protobuf::Closure *done)
311 : {
312 2 : RIALTO_SERVER_LOG_DEBUG("entry:");
313 :
314 2 : MediaKeyErrorStatus status = m_cdmService.setDrmHeader(request->media_keys_handle(), request->key_session_id(),
315 6 : std::vector<std::uint8_t>{request->request_data().begin(),
316 4 : request->request_data().end()});
317 2 : response->set_error_status(convertMediaKeyErrorStatus(status));
318 2 : done->Run();
319 : }
320 :
321 2 : void MediaKeysModuleService::closeKeySession(::google::protobuf::RpcController *controller,
322 : const ::firebolt::rialto::CloseKeySessionRequest *request,
323 : ::firebolt::rialto::CloseKeySessionResponse *response,
324 : ::google::protobuf::Closure *done)
325 : {
326 2 : RIALTO_SERVER_LOG_DEBUG("entry:");
327 :
328 2 : MediaKeyErrorStatus status = m_cdmService.closeKeySession(request->media_keys_handle(), request->key_session_id());
329 2 : response->set_error_status(convertMediaKeyErrorStatus(status));
330 2 : done->Run();
331 : }
332 :
333 2 : void MediaKeysModuleService::removeKeySession(::google::protobuf::RpcController *controller,
334 : const ::firebolt::rialto::RemoveKeySessionRequest *request,
335 : ::firebolt::rialto::RemoveKeySessionResponse *response,
336 : ::google::protobuf::Closure *done)
337 : {
338 2 : RIALTO_SERVER_LOG_DEBUG("entry:");
339 :
340 2 : MediaKeyErrorStatus status = m_cdmService.removeKeySession(request->media_keys_handle(), request->key_session_id());
341 2 : response->set_error_status(convertMediaKeyErrorStatus(status));
342 2 : done->Run();
343 : }
344 :
345 2 : void MediaKeysModuleService::deleteDrmStore(::google::protobuf::RpcController *controller,
346 : const ::firebolt::rialto::DeleteDrmStoreRequest *request,
347 : ::firebolt::rialto::DeleteDrmStoreResponse *response,
348 : ::google::protobuf::Closure *done)
349 : {
350 2 : RIALTO_SERVER_LOG_DEBUG("entry:");
351 :
352 2 : MediaKeyErrorStatus status = m_cdmService.deleteDrmStore(request->media_keys_handle());
353 2 : response->set_error_status(convertMediaKeyErrorStatus(status));
354 2 : done->Run();
355 : }
356 :
357 2 : void MediaKeysModuleService::deleteKeyStore(::google::protobuf::RpcController *controller,
358 : const ::firebolt::rialto::DeleteKeyStoreRequest *request,
359 : ::firebolt::rialto::DeleteKeyStoreResponse *response,
360 : ::google::protobuf::Closure *done)
361 : {
362 2 : RIALTO_SERVER_LOG_DEBUG("entry:");
363 :
364 2 : MediaKeyErrorStatus status = m_cdmService.deleteKeyStore(request->media_keys_handle());
365 2 : response->set_error_status(convertMediaKeyErrorStatus(status));
366 2 : done->Run();
367 : }
368 :
369 2 : void MediaKeysModuleService::getDrmStoreHash(::google::protobuf::RpcController *controller,
370 : const ::firebolt::rialto::GetDrmStoreHashRequest *request,
371 : ::firebolt::rialto::GetDrmStoreHashResponse *response,
372 : ::google::protobuf::Closure *done)
373 : {
374 2 : std::vector<unsigned char> drmStoreHash;
375 2 : RIALTO_SERVER_LOG_DEBUG("entry:");
376 :
377 2 : MediaKeyErrorStatus status = m_cdmService.getDrmStoreHash(request->media_keys_handle(), drmStoreHash);
378 2 : response->set_error_status(convertMediaKeyErrorStatus(status));
379 2 : for (const auto &item : drmStoreHash)
380 : {
381 0 : response->add_drm_store_hash(item);
382 : }
383 2 : done->Run();
384 : }
385 :
386 2 : void MediaKeysModuleService::getKeyStoreHash(::google::protobuf::RpcController *controller,
387 : const ::firebolt::rialto::GetKeyStoreHashRequest *request,
388 : ::firebolt::rialto::GetKeyStoreHashResponse *response,
389 : ::google::protobuf::Closure *done)
390 : {
391 2 : std::vector<unsigned char> keyStoreHash;
392 2 : RIALTO_SERVER_LOG_DEBUG("entry:");
393 :
394 2 : MediaKeyErrorStatus status = m_cdmService.getKeyStoreHash(request->media_keys_handle(), keyStoreHash);
395 2 : response->set_error_status(convertMediaKeyErrorStatus(status));
396 2 : for (const auto &item : keyStoreHash)
397 : {
398 0 : response->add_key_store_hash(item);
399 : }
400 2 : done->Run();
401 : }
402 :
403 2 : void MediaKeysModuleService::getLdlSessionsLimit(::google::protobuf::RpcController *controller,
404 : const ::firebolt::rialto::GetLdlSessionsLimitRequest *request,
405 : ::firebolt::rialto::GetLdlSessionsLimitResponse *response,
406 : ::google::protobuf::Closure *done)
407 : {
408 2 : uint32_t ldlLimit{0};
409 2 : RIALTO_SERVER_LOG_DEBUG("entry:");
410 :
411 2 : MediaKeyErrorStatus status = m_cdmService.getLdlSessionsLimit(request->media_keys_handle(), ldlLimit);
412 2 : response->set_error_status(convertMediaKeyErrorStatus(status));
413 2 : response->set_ldl_limit(ldlLimit);
414 2 : done->Run();
415 : }
416 :
417 2 : void MediaKeysModuleService::getLastDrmError(::google::protobuf::RpcController *controller,
418 : const ::firebolt::rialto::GetLastDrmErrorRequest *request,
419 : ::firebolt::rialto::GetLastDrmErrorResponse *response,
420 : ::google::protobuf::Closure *done)
421 : {
422 2 : uint32_t errorCode{0};
423 2 : RIALTO_SERVER_LOG_DEBUG("entry:");
424 :
425 : MediaKeyErrorStatus status =
426 2 : m_cdmService.getLastDrmError(request->media_keys_handle(), request->key_session_id(), errorCode);
427 2 : response->set_error_status(convertMediaKeyErrorStatus(status));
428 2 : response->set_error_code(errorCode);
429 2 : done->Run();
430 : }
431 :
432 2 : void MediaKeysModuleService::getDrmTime(::google::protobuf::RpcController *controller,
433 : const ::firebolt::rialto::GetDrmTimeRequest *request,
434 : ::firebolt::rialto::GetDrmTimeResponse *response,
435 : ::google::protobuf::Closure *done)
436 : {
437 2 : uint64_t drmTime{0};
438 2 : RIALTO_SERVER_LOG_DEBUG("entry:");
439 :
440 2 : MediaKeyErrorStatus status = m_cdmService.getDrmTime(request->media_keys_handle(), drmTime);
441 2 : response->set_error_status(convertMediaKeyErrorStatus(status));
442 2 : response->set_drm_time(drmTime);
443 2 : done->Run();
444 : }
445 :
446 2 : void MediaKeysModuleService::getCdmKeySessionId(::google::protobuf::RpcController *controller,
447 : const ::firebolt::rialto::GetCdmKeySessionIdRequest *request,
448 : ::firebolt::rialto::GetCdmKeySessionIdResponse *response,
449 : ::google::protobuf::Closure *done)
450 : {
451 2 : RIALTO_SERVER_LOG_DEBUG("entry:");
452 :
453 2 : std::string cdmKeySessionId;
454 : MediaKeyErrorStatus status =
455 2 : m_cdmService.getCdmKeySessionId(request->media_keys_handle(), request->key_session_id(), cdmKeySessionId);
456 2 : response->set_error_status(convertMediaKeyErrorStatus(status));
457 2 : response->set_cdm_key_session_id(cdmKeySessionId);
458 2 : done->Run();
459 : }
460 :
461 2 : void MediaKeysModuleService::releaseKeySession(::google::protobuf::RpcController *controller,
462 : const ::firebolt::rialto::ReleaseKeySessionRequest *request,
463 : ::firebolt::rialto::ReleaseKeySessionResponse *response,
464 : ::google::protobuf::Closure *done)
465 : {
466 2 : RIALTO_SERVER_LOG_DEBUG("entry:");
467 :
468 2 : MediaKeyErrorStatus status = m_cdmService.releaseKeySession(request->media_keys_handle(), request->key_session_id());
469 2 : response->set_error_status(convertMediaKeyErrorStatus(status));
470 2 : done->Run();
471 : }
472 :
473 : } // namespace firebolt::rialto::server::ipc
|