blob: 92ea50074d1192565f7ca460725f656e9ba3efe1 [file] [log] [blame]
// 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 <sstream>
#include <utility>
#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 <TargetConditionals.h>
#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<int>(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