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