// Copyright 2019 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "cast/common/channel/message_util.h" #include #include #include "cast/common/channel/virtual_connection.h" #include "util/json/json_serialization.h" #include "util/json/json_value.h" #include "util/osp_logging.h" #if defined(__APPLE__) || defined(__MACH__) #include #endif namespace openscreen { namespace cast { namespace { using ::cast::channel::CastMessage; // The value used for "sdkType" in a virtual CONNECT request. Historically, this // value was used in Chrome's C++ impl even though "2" refers to the Media // Router Extension. constexpr int kVirtualConnectSdkType = 2; // The value used for "connectionType" in a virtual CONNECT request. This value // stands for CONNECTION_TYPE_LOCAL. constexpr int kVirtualConnectTypeLocal = 1; // The value to be set as the "platform" value in a virtual CONNECT request. // Source (in Chromium source tree): // src/third_party/metrics_proto/cast_logs.proto enum VirtualConnectPlatformValue { kOtherPlatform = 0, kAndroid = 1, kIOS = 2, kWindows = 3, kMacOSX = 4, kChromeOS = 5, kLinux = 6, kCastDevice = 7, }; #if defined(__APPLE__) || defined(__MACH__) constexpr VirtualConnectPlatformValue GetVirtualConnectPlatformMacFlavor() { #if defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE return kIOS; #else return kMacOSX; #endif } #endif constexpr VirtualConnectPlatformValue GetVirtualConnectPlatform() { // Based on //build/build_config.h in the Chromium project. The order of these // matters! #if defined(__ANDROID__) return kAndroid; #elif defined(__APPLE__) || defined(__MACH__) return GetVirtualConnectPlatformMacFlavor(); #elif defined(_WIN32) || defined(_WIN64) return kWindows; #elif defined(OS_CHROMEOS) // Note: OS_CHROMEOS is defined via the compiler's command line in Chromium // embedder builds by Chromium's //build/config/linux:runtime_library config. return kChromeOS; #elif defined(__linux__) return kLinux; #else return kOtherPlatform; #endif } CastMessage MakeConnectionMessage(const std::string& source_id, const std::string& destination_id) { CastMessage connect_message; connect_message.set_protocol_version(kDefaultOutgoingMessageVersion); connect_message.set_source_id(source_id); connect_message.set_destination_id(destination_id); connect_message.set_namespace_(kConnectionNamespace); return connect_message; } } // namespace std::string ToString(AppAvailabilityResult availability) { switch (availability) { case AppAvailabilityResult::kAvailable: return "Available"; case AppAvailabilityResult::kUnavailable: return "Unavailable"; case AppAvailabilityResult::kUnknown: return "Unknown"; default: OSP_NOTREACHED(); } } CastMessage MakeSimpleUTF8Message(const std::string& namespace_, std::string payload) { CastMessage message; message.set_protocol_version(kDefaultOutgoingMessageVersion); message.set_namespace_(namespace_); message.set_payload_type(::cast::channel::CastMessage_PayloadType_STRING); message.set_payload_utf8(std::move(payload)); return message; } CastMessage MakeConnectMessage(const std::string& source_id, const std::string& destination_id) { CastMessage connect_message = MakeConnectionMessage(source_id, destination_id); connect_message.set_payload_type( ::cast::channel::CastMessage_PayloadType_STRING); // Historically, the CONNECT message was meant to come from a Chrome browser. // However, this library could be embedded in any app. So, properties like // user agent, application version, etc. are not known here. static constexpr char kUnknownVersion[] = "Unknown (Open Screen)"; Json::Value message(Json::objectValue); message[kMessageKeyType] = CastMessageTypeToString(CastMessageType::kConnect); for (int i = 0; i <= 3; ++i) { message[kMessageKeyProtocolVersionList][i] = ::cast::channel::CastMessage_ProtocolVersion_CASTV2_1_0 + i; } message[kMessageKeyUserAgent] = kUnknownVersion; message[kMessageKeyConnType] = static_cast(VirtualConnection::Type::kStrong); message[kMessageKeyOrigin] = Json::Value(Json::objectValue); Json::Value sender_info(Json::objectValue); sender_info[kMessageKeySdkType] = kVirtualConnectSdkType; sender_info[kMessageKeyVersion] = kUnknownVersion; sender_info[kMessageKeyBrowserVersion] = kUnknownVersion; sender_info[kMessageKeyPlatform] = GetVirtualConnectPlatform(); sender_info[kMessageKeyConnectionType] = kVirtualConnectTypeLocal; message[kMessageKeySenderInfo] = std::move(sender_info); connect_message.set_payload_utf8(json::Stringify(std::move(message)).value()); return connect_message; } CastMessage MakeCloseMessage(const std::string& source_id, const std::string& destination_id) { CastMessage close_message = MakeConnectionMessage(source_id, destination_id); close_message.set_payload_type( ::cast::channel::CastMessage_PayloadType_STRING); close_message.set_payload_utf8(R"!({"type": "CLOSE"})!"); return close_message; } std::string MakeUniqueSessionId(const char* prefix) { static int next_id = 10000; std::ostringstream oss; oss << prefix << '-' << (next_id++); return oss.str(); } } // namespace cast } // namespace openscreen