// Copyright 2020 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include "core/internal/offline_frames.h" #include #include #include "core/internal/message_lite.h" #include "core/internal/offline_frames_validator.h" #include "core/status.h" #include "platform/base/byte_array.h" namespace location { namespace nearby { namespace connections { namespace parser { namespace { using ExceptionOrOfflineFrame = ExceptionOr; using MessageLite = ::google::protobuf::MessageLite; ByteArray ToBytes(OfflineFrame&& frame) { ByteArray bytes(frame.ByteSizeLong()); frame.set_version(OfflineFrame::V1); frame.SerializeToArray(bytes.data(), bytes.size()); return bytes; } } // namespace ExceptionOrOfflineFrame FromBytes(const ByteArray& bytes) { OfflineFrame frame; if (frame.ParseFromString(std::string(bytes))) { Exception validation_exception = EnsureValidOfflineFrame(frame); if (validation_exception.Raised()) { return ExceptionOrOfflineFrame(validation_exception); } return ExceptionOrOfflineFrame(std::move(frame)); } else { return ExceptionOrOfflineFrame(Exception::kInvalidProtocolBuffer); } } V1Frame::FrameType GetFrameType(const OfflineFrame& frame) { if ((frame.version() == OfflineFrame::V1) && frame.has_v1()) { return frame.v1().type(); } return V1Frame::UNKNOWN_FRAME_TYPE; } ByteArray ForConnectionRequest(const std::string& endpoint_id, const ByteArray& endpoint_info, std::int32_t nonce, bool supports_5_ghz, const std::string& bssid, const std::vector& mediums, std::int32_t keep_alive_interval_millis, std::int32_t keep_alive_timeout_millis) { OfflineFrame frame; frame.set_version(OfflineFrame::V1); auto* v1_frame = frame.mutable_v1(); v1_frame->set_type(V1Frame::CONNECTION_REQUEST); auto* connection_request = v1_frame->mutable_connection_request(); if (!endpoint_id.empty()) connection_request->set_endpoint_id(endpoint_id); if (!endpoint_info.Empty()) { connection_request->set_endpoint_name(std::string(endpoint_info)); connection_request->set_endpoint_info(std::string(endpoint_info)); } connection_request->set_nonce(nonce); auto* medium_metadata = connection_request->mutable_medium_metadata(); medium_metadata->set_supports_5_ghz(supports_5_ghz); if (!bssid.empty()) medium_metadata->set_bssid(bssid); if (!mediums.empty()) { for (const auto& medium : mediums) { connection_request->add_mediums(MediumToConnectionRequestMedium(medium)); } } if (keep_alive_interval_millis > 0) { connection_request->set_keep_alive_interval_millis( keep_alive_interval_millis); } if (keep_alive_timeout_millis > 0) { connection_request->set_keep_alive_timeout_millis( keep_alive_timeout_millis); } return ToBytes(std::move(frame)); } ByteArray ForConnectionResponse(std::int32_t status) { OfflineFrame frame; frame.set_version(OfflineFrame::V1); auto* v1_frame = frame.mutable_v1(); v1_frame->set_type(V1Frame::CONNECTION_RESPONSE); auto* sub_frame = v1_frame->mutable_connection_response(); // For backward compatiblility, here still sets both status and response // parameters until the response feature is roll out in all supported // devices. sub_frame->set_status(status); sub_frame->set_response(status == Status::kSuccess ? ConnectionResponseFrame::ACCEPT : ConnectionResponseFrame::REJECT); return ToBytes(std::move(frame)); } ByteArray ForDataPayloadTransfer( const PayloadTransferFrame::PayloadHeader& header, const PayloadTransferFrame::PayloadChunk& chunk) { OfflineFrame frame; frame.set_version(OfflineFrame::V1); auto* v1_frame = frame.mutable_v1(); v1_frame->set_type(V1Frame::PAYLOAD_TRANSFER); auto* sub_frame = v1_frame->mutable_payload_transfer(); sub_frame->set_packet_type(PayloadTransferFrame::DATA); *sub_frame->mutable_payload_header() = header; *sub_frame->mutable_payload_chunk() = chunk; return ToBytes(std::move(frame)); } ByteArray ForControlPayloadTransfer( const PayloadTransferFrame::PayloadHeader& header, const PayloadTransferFrame::ControlMessage& control) { OfflineFrame frame; frame.set_version(OfflineFrame::V1); auto* v1_frame = frame.mutable_v1(); v1_frame->set_type(V1Frame::PAYLOAD_TRANSFER); auto* sub_frame = v1_frame->mutable_payload_transfer(); sub_frame->set_packet_type(PayloadTransferFrame::CONTROL); *sub_frame->mutable_payload_header() = header; *sub_frame->mutable_control_message() = control; return ToBytes(std::move(frame)); } ByteArray ForBwuWifiHotspotPathAvailable(const std::string& ssid, const std::string& password, std::int32_t port, const std::string& gateway, bool supports_disabling_encryption) { OfflineFrame frame; frame.set_version(OfflineFrame::V1); auto* v1_frame = frame.mutable_v1(); v1_frame->set_type(V1Frame::BANDWIDTH_UPGRADE_NEGOTIATION); auto* sub_frame = v1_frame->mutable_bandwidth_upgrade_negotiation(); sub_frame->set_event_type( BandwidthUpgradeNegotiationFrame::UPGRADE_PATH_AVAILABLE); auto* upgrade_path_info = sub_frame->mutable_upgrade_path_info(); upgrade_path_info->set_medium(UpgradePathInfo::WIFI_HOTSPOT); upgrade_path_info->set_supports_client_introduction_ack(true); upgrade_path_info->set_supports_disabling_encryption( supports_disabling_encryption); auto* wifi_hotspot_credentials = upgrade_path_info->mutable_wifi_hotspot_credentials(); wifi_hotspot_credentials->set_ssid(ssid); wifi_hotspot_credentials->set_password(password); wifi_hotspot_credentials->set_port(port); wifi_hotspot_credentials->set_gateway(gateway); return ToBytes(std::move(frame)); } ByteArray ForBwuWifiLanPathAvailable(const std::string& ip_address, std::int32_t port) { OfflineFrame frame; frame.set_version(OfflineFrame::V1); auto* v1_frame = frame.mutable_v1(); v1_frame->set_type(V1Frame::BANDWIDTH_UPGRADE_NEGOTIATION); auto* sub_frame = v1_frame->mutable_bandwidth_upgrade_negotiation(); sub_frame->set_event_type( BandwidthUpgradeNegotiationFrame::UPGRADE_PATH_AVAILABLE); auto* upgrade_path_info = sub_frame->mutable_upgrade_path_info(); upgrade_path_info->set_medium(UpgradePathInfo::WIFI_LAN); upgrade_path_info->set_supports_client_introduction_ack(true); auto* wifi_lan_socket = upgrade_path_info->mutable_wifi_lan_socket(); wifi_lan_socket->set_ip_address(ip_address); wifi_lan_socket->set_wifi_port(port); return ToBytes(std::move(frame)); } ByteArray ForBwuWifiAwarePathAvailable(const std::string& service_id, const std::string& service_info, const std::string& password, bool supports_disabling_encryption) { OfflineFrame frame; frame.set_version(OfflineFrame::V1); auto* v1_frame = frame.mutable_v1(); v1_frame->set_type(V1Frame::BANDWIDTH_UPGRADE_NEGOTIATION); auto* sub_frame = v1_frame->mutable_bandwidth_upgrade_negotiation(); sub_frame->set_event_type( BandwidthUpgradeNegotiationFrame::UPGRADE_PATH_AVAILABLE); auto* upgrade_path_info = sub_frame->mutable_upgrade_path_info(); upgrade_path_info->set_medium(UpgradePathInfo::WIFI_AWARE); upgrade_path_info->set_supports_client_introduction_ack(true); upgrade_path_info->set_supports_disabling_encryption( supports_disabling_encryption); auto* wifi_aware_credentials = upgrade_path_info->mutable_wifi_aware_credentials(); wifi_aware_credentials->set_service_id(service_id); wifi_aware_credentials->set_service_info(service_info); if (!password.empty()) wifi_aware_credentials->set_password(password); return ToBytes(std::move(frame)); } ByteArray ForBwuWifiDirectPathAvailable(const std::string& ssid, const std::string& password, std::int32_t port, std::int32_t frequency, bool supports_disabling_encryption) { OfflineFrame frame; frame.set_version(OfflineFrame::V1); auto* v1_frame = frame.mutable_v1(); v1_frame->set_type(V1Frame::BANDWIDTH_UPGRADE_NEGOTIATION); auto* sub_frame = v1_frame->mutable_bandwidth_upgrade_negotiation(); sub_frame->set_event_type( BandwidthUpgradeNegotiationFrame::UPGRADE_PATH_AVAILABLE); auto* upgrade_path_info = sub_frame->mutable_upgrade_path_info(); upgrade_path_info->set_medium(UpgradePathInfo::WIFI_DIRECT); upgrade_path_info->set_supports_client_introduction_ack(true); upgrade_path_info->set_supports_disabling_encryption( supports_disabling_encryption); auto* wifi_direct_credentials = upgrade_path_info->mutable_wifi_direct_credentials(); wifi_direct_credentials->set_ssid(ssid); wifi_direct_credentials->set_password(password); wifi_direct_credentials->set_port(port); wifi_direct_credentials->set_frequency(frequency); return ToBytes(std::move(frame)); } ByteArray ForBwuBluetoothPathAvailable(const std::string& service_id, const std::string& mac_address) { OfflineFrame frame; frame.set_version(OfflineFrame::V1); auto* v1_frame = frame.mutable_v1(); v1_frame->set_type(V1Frame::BANDWIDTH_UPGRADE_NEGOTIATION); auto* sub_frame = v1_frame->mutable_bandwidth_upgrade_negotiation(); sub_frame->set_event_type( BandwidthUpgradeNegotiationFrame::UPGRADE_PATH_AVAILABLE); auto* upgrade_path_info = sub_frame->mutable_upgrade_path_info(); upgrade_path_info->set_medium(UpgradePathInfo::BLUETOOTH); upgrade_path_info->set_supports_client_introduction_ack(true); auto* bluetooth_credentials = upgrade_path_info->mutable_bluetooth_credentials(); bluetooth_credentials->set_mac_address(mac_address); bluetooth_credentials->set_service_name(service_id); return ToBytes(std::move(frame)); } ByteArray ForBwuWebrtcPathAvailable(const std::string& peer_id, const LocationHint& location_hint) { OfflineFrame frame; frame.set_version(OfflineFrame::V1); auto* v1_frame = frame.mutable_v1(); v1_frame->set_type(V1Frame::BANDWIDTH_UPGRADE_NEGOTIATION); auto* sub_frame = v1_frame->mutable_bandwidth_upgrade_negotiation(); sub_frame->set_event_type( BandwidthUpgradeNegotiationFrame::UPGRADE_PATH_AVAILABLE); auto* upgrade_path_info = sub_frame->mutable_upgrade_path_info(); upgrade_path_info->set_medium(UpgradePathInfo::WEB_RTC); upgrade_path_info->set_supports_client_introduction_ack(true); auto* webrtc_credentials = upgrade_path_info->mutable_web_rtc_credentials(); webrtc_credentials->set_peer_id(peer_id); auto* local_location_hint = webrtc_credentials->mutable_location_hint(); *local_location_hint = location_hint; return ToBytes(std::move(frame)); } ByteArray ForBwuLastWrite() { OfflineFrame frame; frame.set_version(OfflineFrame::V1); auto* v1_frame = frame.mutable_v1(); v1_frame->set_type(V1Frame::BANDWIDTH_UPGRADE_NEGOTIATION); auto* sub_frame = v1_frame->mutable_bandwidth_upgrade_negotiation(); sub_frame->set_event_type( BandwidthUpgradeNegotiationFrame::LAST_WRITE_TO_PRIOR_CHANNEL); return ToBytes(std::move(frame)); } ByteArray ForBwuSafeToClose() { OfflineFrame frame; frame.set_version(OfflineFrame::V1); auto* v1_frame = frame.mutable_v1(); v1_frame->set_type(V1Frame::BANDWIDTH_UPGRADE_NEGOTIATION); auto* sub_frame = v1_frame->mutable_bandwidth_upgrade_negotiation(); sub_frame->set_event_type( BandwidthUpgradeNegotiationFrame::SAFE_TO_CLOSE_PRIOR_CHANNEL); return ToBytes(std::move(frame)); } ByteArray ForBwuIntroduction(const std::string& endpoint_id) { OfflineFrame frame; frame.set_version(OfflineFrame::V1); auto* v1_frame = frame.mutable_v1(); v1_frame->set_type(V1Frame::BANDWIDTH_UPGRADE_NEGOTIATION); auto* sub_frame = v1_frame->mutable_bandwidth_upgrade_negotiation(); sub_frame->set_event_type( BandwidthUpgradeNegotiationFrame::CLIENT_INTRODUCTION); auto* client_introduction = sub_frame->mutable_client_introduction(); client_introduction->set_endpoint_id(endpoint_id); return ToBytes(std::move(frame)); } ByteArray ForBwuIntroductionAck() { OfflineFrame frame; frame.set_version(OfflineFrame::V1); auto* v1_frame = frame.mutable_v1(); v1_frame->set_type(V1Frame::BANDWIDTH_UPGRADE_NEGOTIATION); auto* sub_frame = v1_frame->mutable_bandwidth_upgrade_negotiation(); sub_frame->set_event_type( BandwidthUpgradeNegotiationFrame::CLIENT_INTRODUCTION_ACK); return ToBytes(std::move(frame)); } ByteArray ForBwuFailure(const UpgradePathInfo& info) { OfflineFrame frame; frame.set_version(OfflineFrame::V1); auto* v1_frame = frame.mutable_v1(); v1_frame->set_type(V1Frame::BANDWIDTH_UPGRADE_NEGOTIATION); auto* sub_frame = v1_frame->mutable_bandwidth_upgrade_negotiation(); sub_frame->set_event_type(BandwidthUpgradeNegotiationFrame::UPGRADE_FAILURE); auto* upgrade_path_info = sub_frame->mutable_upgrade_path_info(); *upgrade_path_info = info; return ToBytes(std::move(frame)); } ByteArray ForKeepAlive() { OfflineFrame frame; frame.set_version(OfflineFrame::V1); auto* v1_frame = frame.mutable_v1(); v1_frame->set_type(V1Frame::KEEP_ALIVE); v1_frame->mutable_keep_alive(); return ToBytes(std::move(frame)); } ByteArray ForDisconnection() { OfflineFrame frame; frame.set_version(OfflineFrame::V1); auto* v1_frame = frame.mutable_v1(); v1_frame->set_type(V1Frame::DISCONNECTION); v1_frame->mutable_disconnection(); return ToBytes(std::move(frame)); } UpgradePathInfo::Medium MediumToUpgradePathInfoMedium(Medium medium) { switch (medium) { case Medium::MDNS: return UpgradePathInfo::MDNS; case Medium::BLUETOOTH: return UpgradePathInfo::BLUETOOTH; case Medium::WIFI_HOTSPOT: return UpgradePathInfo::WIFI_HOTSPOT; case Medium::BLE: return UpgradePathInfo::BLE; case Medium::WIFI_LAN: return UpgradePathInfo::WIFI_LAN; case Medium::WIFI_AWARE: return UpgradePathInfo::WIFI_AWARE; case Medium::NFC: return UpgradePathInfo::NFC; case Medium::WIFI_DIRECT: return UpgradePathInfo::WIFI_DIRECT; case Medium::WEB_RTC: return UpgradePathInfo::WEB_RTC; default: return UpgradePathInfo::UNKNOWN_MEDIUM; } } Medium UpgradePathInfoMediumToMedium(UpgradePathInfo::Medium medium) { switch (medium) { case UpgradePathInfo::MDNS: return Medium::MDNS; case UpgradePathInfo::BLUETOOTH: return Medium::BLUETOOTH; case UpgradePathInfo::WIFI_HOTSPOT: return Medium::WIFI_HOTSPOT; case UpgradePathInfo::BLE: return Medium::BLE; case UpgradePathInfo::WIFI_LAN: return Medium::WIFI_LAN; case UpgradePathInfo::WIFI_AWARE: return Medium::WIFI_AWARE; case UpgradePathInfo::NFC: return Medium::NFC; case UpgradePathInfo::WIFI_DIRECT: return Medium::WIFI_DIRECT; case UpgradePathInfo::WEB_RTC: return Medium::WEB_RTC; default: return Medium::UNKNOWN_MEDIUM; } } ConnectionRequestFrame::Medium MediumToConnectionRequestMedium(Medium medium) { switch (medium) { case Medium::MDNS: return ConnectionRequestFrame::MDNS; case Medium::BLUETOOTH: return ConnectionRequestFrame::BLUETOOTH; case Medium::WIFI_HOTSPOT: return ConnectionRequestFrame::WIFI_HOTSPOT; case Medium::BLE: return ConnectionRequestFrame::BLE; case Medium::WIFI_LAN: return ConnectionRequestFrame::WIFI_LAN; case Medium::WIFI_AWARE: return ConnectionRequestFrame::WIFI_AWARE; case Medium::NFC: return ConnectionRequestFrame::NFC; case Medium::WIFI_DIRECT: return ConnectionRequestFrame::WIFI_DIRECT; case Medium::WEB_RTC: return ConnectionRequestFrame::WEB_RTC; default: return ConnectionRequestFrame::UNKNOWN_MEDIUM; } } Medium ConnectionRequestMediumToMedium(ConnectionRequestFrame::Medium medium) { switch (medium) { case ConnectionRequestFrame::MDNS: return Medium::MDNS; case ConnectionRequestFrame::BLUETOOTH: return Medium::BLUETOOTH; case ConnectionRequestFrame::WIFI_HOTSPOT: return Medium::WIFI_HOTSPOT; case ConnectionRequestFrame::BLE: return Medium::BLE; case ConnectionRequestFrame::WIFI_LAN: return Medium::WIFI_LAN; case ConnectionRequestFrame::WIFI_AWARE: return Medium::WIFI_AWARE; case ConnectionRequestFrame::NFC: return Medium::NFC; case ConnectionRequestFrame::WIFI_DIRECT: return Medium::WIFI_DIRECT; case ConnectionRequestFrame::WEB_RTC: return Medium::WEB_RTC; default: return Medium::UNKNOWN_MEDIUM; } } std::vector ConnectionRequestMediumsToMediums( const ConnectionRequestFrame& frame) { std::vector result; for (const auto& int_medium : frame.mediums()) { result.push_back(ConnectionRequestMediumToMedium( static_cast(int_medium))); } return result; } } // namespace parser } // namespace connections } // namespace nearby } // namespace location