///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
| 463 | |
| 464 | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
| 465 | void FSecure::C3::Core::Profiler::Agent::ParseAndRunCommand(json const& jCommandElement) noexcept(false) |
| 466 | { |
| 467 | auto profiler = m_Owner.lock(); |
| 468 | if (!profiler) |
| 469 | return; // probably shutting down |
| 470 | |
| 471 | // check if the command should be run on device |
| 472 | std::optional<DeviceId> deviceId; |
| 473 | bool deviceIsChannel = false; // have meaning only when it is command for device. |
| 474 | if (auto jChannelId = jCommandElement.find("channelId"); jChannelId != jCommandElement.end() && !jChannelId->is_null()) |
| 475 | { |
| 476 | if (auto channel = m_Channels.Find(jChannelId->get<std::string>()); channel) |
| 477 | { |
| 478 | deviceId = channel->m_Id; |
| 479 | deviceIsChannel = true; |
| 480 | } |
| 481 | else |
| 482 | throw std::runtime_error{ "Unknown ChannelId." }; |
| 483 | } |
| 484 | else if (auto jPeripheralId = jCommandElement.find("peripheralId"); jPeripheralId != jCommandElement.end() && !jPeripheralId->is_null()) |
| 485 | { |
| 486 | if (auto peripheral = m_Peripherals.Find(jPeripheralId->get<std::string>()); peripheral) |
| 487 | deviceId = peripheral->m_Id; |
| 488 | else |
| 489 | throw std::runtime_error{ "Unknown PeripheralId." }; |
| 490 | } |
| 491 | |
| 492 | auto commandWithArgs = base64::decode<ByteVector>(jCommandElement["Command"]["ByteForm"].get<std::string>()); |
| 493 | |
| 494 | auto gateRelay = profiler->m_Gateway->m_Gateway.lock(); |
| 495 | if (!gateRelay) |
| 496 | return; // probably shutting down |
| 497 | |
| 498 | if (deviceId) |
| 499 | { |
| 500 | std::function<void()> finalizer = []() {}; |
| 501 | |
| 502 | auto commandReadView = ByteView{ commandWithArgs }; |
| 503 | auto commandId = commandReadView.Read<std::uint16_t>(); |
| 504 | if (commandId > static_cast<std::uint16_t>(-256)) |
| 505 | { |
| 506 | // generic interface commands |
| 507 | switch (static_cast<FSecure::C3::Command>(commandId)) |
| 508 | { |
| 509 | case FSecure::C3::Command::Close: |
| 510 | finalizer = [&]() |
| 511 | { |
| 512 | if (deviceIsChannel) |
| 513 | { |
| 514 | m_Channels.TryRemove(*deviceId); |
| 515 | m_Routes.RemoveIf([deviceId](Profiler::Route const& route) { return route.m_OutgoingDevice == deviceId; }); |
| 516 | } |
| 517 | else |
| 518 | { |
| 519 | // Find connector hash |
| 520 | auto element = m_Peripherals.Find(*deviceId); |
| 521 | if (!element) |
| 522 | return; |
no test coverage detected