aboutsummaryrefslogtreecommitdiff
path: root/cast/sender
diff options
context:
space:
mode:
authorbtolsch <btolsch@chromium.org>2019-10-01 11:39:33 -0700
committerCommit Bot <commit-bot@chromium.org>2019-10-01 20:24:53 +0000
commit9dd4cf87c1214381e72be6b9e1c4af33417e8f99 (patch)
tree9769ab2c497ed03ff6dac98bec5bfc77434fd36e /cast/sender
parent5dc91624a6d9d1369769eab8b603399744cdd63c (diff)
downloadopenscreen-9dd4cf87c1214381e72be6b9e1c4af33417e8f99.tar.gz
Add CastSocket and implementation
This change adds a CastSocket interface to handle sending and receiving CastMessage structures along with an implementation that uses the platform TlsConnection for transport. Bug: openscreen:59 Change-Id: I92dc29b45efb2b1657a2ff6d962f1ed670311370 Reviewed-on: https://chromium-review.googlesource.com/c/openscreen/+/1825511 Commit-Queue: Brandon Tolsch <btolsch@chromium.org> Reviewed-by: Ryan Keane <rwkeane@google.com>
Diffstat (limited to 'cast/sender')
-rw-r--r--cast/sender/channel/BUILD.gn10
-rw-r--r--cast/sender/channel/cast_auth_util.h2
-rw-r--r--cast/sender/channel/cast_auth_util_unittest.cc2
-rw-r--r--cast/sender/channel/cast_framer.cc94
-rw-r--r--cast/sender/channel/cast_framer.h59
-rw-r--r--cast/sender/channel/cast_framer_unittest.cc179
-rw-r--r--cast/sender/channel/proto/BUILD.gn11
-rw-r--r--cast/sender/channel/proto/cast_channel.proto99
8 files changed, 4 insertions, 452 deletions
diff --git a/cast/sender/channel/BUILD.gn b/cast/sender/channel/BUILD.gn
index 13b061c1..85f633b0 100644
--- a/cast/sender/channel/BUILD.gn
+++ b/cast/sender/channel/BUILD.gn
@@ -6,18 +6,14 @@ source_set("channel") {
sources = [
"cast_auth_util.cc",
"cast_auth_util.h",
- "cast_framer.cc",
- "cast_framer.h",
]
deps = [
- "../../../util",
- "proto",
+ "../../common/channel/proto",
]
public_deps = [
"../../../platform",
- "../../../third_party/abseil",
]
}
@@ -25,15 +21,13 @@ source_set("unittests") {
testonly = true
sources = [
"cast_auth_util_unittest.cc",
- "cast_framer_unittest.cc",
]
deps = [
":channel",
"../../../platform",
"../../../third_party/googletest:gtest",
- "../../../util",
"../../common/certificate/proto:unittest_proto",
- "proto",
+ "../../common/channel/proto",
]
}
diff --git a/cast/sender/channel/cast_auth_util.h b/cast/sender/channel/cast_auth_util.h
index b4a81e0b..35f1d028 100644
--- a/cast/sender/channel/cast_auth_util.h
+++ b/cast/sender/channel/cast_auth_util.h
@@ -10,7 +10,7 @@
#include <string>
#include "cast/common/certificate/cast_cert_validator.h"
-#include "cast/sender/channel/proto/cast_channel.pb.h"
+#include "cast/common/channel/proto/cast_channel.pb.h"
#include "platform/base/error.h"
namespace cast {
diff --git a/cast/sender/channel/cast_auth_util_unittest.cc b/cast/sender/channel/cast_auth_util_unittest.cc
index 10819362..61d49aa1 100644
--- a/cast/sender/channel/cast_auth_util_unittest.cc
+++ b/cast/sender/channel/cast_auth_util_unittest.cc
@@ -10,7 +10,7 @@
#include "cast/common/certificate/cast_crl.h"
#include "cast/common/certificate/proto/test_suite.pb.h"
#include "cast/common/certificate/test_helpers.h"
-#include "cast/sender/channel/proto/cast_channel.pb.h"
+#include "cast/common/channel/proto/cast_channel.pb.h"
#include "gtest/gtest.h"
#include "platform/api/logging.h"
#include "platform/api/time.h"
diff --git a/cast/sender/channel/cast_framer.cc b/cast/sender/channel/cast_framer.cc
deleted file mode 100644
index b5a8acb1..00000000
--- a/cast/sender/channel/cast_framer.cc
+++ /dev/null
@@ -1,94 +0,0 @@
-// 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/sender/channel/cast_framer.h"
-
-#include <stdlib.h>
-#include <string.h>
-
-#include <limits>
-
-#include "cast/sender/channel/proto/cast_channel.pb.h"
-#include "platform/api/logging.h"
-#include "util/big_endian.h"
-#include "util/std_util.h"
-
-namespace cast {
-namespace channel {
-
-using ChannelError = openscreen::Error::Code;
-
-namespace {
-
-static constexpr size_t kHeaderSize = sizeof(uint32_t);
-
-// Cast specifies a max message body size of 64 KiB.
-static constexpr size_t kMaxBodySize = 65536;
-
-} // namespace
-
-MessageFramer::MessageFramer(absl::Span<uint8_t> input_buffer)
- : input_buffer_(input_buffer) {}
-
-MessageFramer::~MessageFramer() = default;
-
-// static
-ErrorOr<std::string> MessageFramer::Serialize(const CastMessage& message) {
- const size_t message_size = message.ByteSizeLong();
- if (message_size > kMaxBodySize || message_size == 0) {
- return ChannelError::kCastV2InvalidMessage;
- }
- std::string out(message_size + kHeaderSize, 0);
- openscreen::WriteBigEndian<uint32_t>(message_size, openscreen::data(out));
- if (!message.SerializeToArray(&out[kHeaderSize], message_size)) {
- return ChannelError::kCastV2InvalidMessage;
- }
- return out;
-}
-
-ErrorOr<size_t> MessageFramer::BytesRequested() const {
- if (message_bytes_received_ < kHeaderSize) {
- return kHeaderSize - message_bytes_received_;
- }
-
- const uint32_t message_size =
- openscreen::ReadBigEndian<uint32_t>(input_buffer_.data());
- if (message_size > kMaxBodySize) {
- return ChannelError::kCastV2InvalidMessage;
- }
- return (kHeaderSize + message_size) - message_bytes_received_;
-}
-
-ErrorOr<CastMessage> MessageFramer::TryDeserialize(size_t byte_count) {
- message_bytes_received_ += byte_count;
- if (message_bytes_received_ > input_buffer_.size()) {
- return ChannelError::kCastV2InvalidMessage;
- }
-
- if (message_bytes_received_ < kHeaderSize) {
- return ChannelError::kInsufficientBuffer;
- }
-
- const uint32_t message_size =
- openscreen::ReadBigEndian<uint32_t>(input_buffer_.data());
- if (message_size > kMaxBodySize) {
- return ChannelError::kCastV2InvalidMessage;
- }
-
- if (message_bytes_received_ < (kHeaderSize + message_size)) {
- return ChannelError::kInsufficientBuffer;
- }
-
- CastMessage parsed_message;
- if (!parsed_message.ParseFromArray(input_buffer_.data() + kHeaderSize,
- message_size)) {
- return ChannelError::kCastV2InvalidMessage;
- }
-
- message_bytes_received_ = 0;
- return parsed_message;
-}
-
-} // namespace channel
-} // namespace cast
diff --git a/cast/sender/channel/cast_framer.h b/cast/sender/channel/cast_framer.h
deleted file mode 100644
index 8fbabfd3..00000000
--- a/cast/sender/channel/cast_framer.h
+++ /dev/null
@@ -1,59 +0,0 @@
-// 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.
-
-#ifndef CAST_SENDER_CHANNEL_CAST_FRAMER_H_
-#define CAST_SENDER_CHANNEL_CAST_FRAMER_H_
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include <memory>
-#include <string>
-
-#include "absl/types/span.h"
-#include "platform/base/error.h"
-
-namespace cast {
-namespace channel {
-
-class CastMessage;
-
-using openscreen::ErrorOr;
-
-// Class for constructing and parsing CastMessage packet data.
-class MessageFramer {
- public:
- // Serializes |message_proto| into |message_data|.
- // Returns true if the message was serialized successfully, false otherwise.
- static ErrorOr<std::string> Serialize(const CastMessage& message);
-
- explicit MessageFramer(absl::Span<uint8_t> input_buffer);
- ~MessageFramer();
-
- // The number of bytes required from the next |input_buffer| passed to
- // TryDeserialize to complete the CastMessage being read. Returns zero if
- // there has been a parsing error.
- ErrorOr<size_t> BytesRequested() const;
-
- // Reads bytes from |input_buffer_| and returns a new CastMessage if one is
- // fully read.
- //
- // |byte_count| Number of additional bytes available in |input_buffer_|.
- // Returns a pointer to a parsed CastMessage if a message was received in its
- // entirety, empty unique_ptr if parsing was successful but didn't produce a
- // complete message, and an error otherwise.
- ErrorOr<CastMessage> TryDeserialize(size_t byte_count);
-
- private:
- // Total size of the message received so far in bytes (head + body).
- size_t message_bytes_received_ = 0;
-
- // Data buffer wherein the caller should place message data for ingest.
- absl::Span<uint8_t> input_buffer_;
-};
-
-} // namespace channel
-} // namespace cast
-
-#endif // CAST_SENDER_CHANNEL_CAST_FRAMER_H_
diff --git a/cast/sender/channel/cast_framer_unittest.cc b/cast/sender/channel/cast_framer_unittest.cc
deleted file mode 100644
index 0cd10c71..00000000
--- a/cast/sender/channel/cast_framer_unittest.cc
+++ /dev/null
@@ -1,179 +0,0 @@
-// 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/sender/channel/cast_framer.h"
-
-#include <stddef.h>
-
-#include <algorithm>
-#include <string>
-
-#include "cast/sender/channel/proto/cast_channel.pb.h"
-#include "gtest/gtest.h"
-#include "util/big_endian.h"
-#include "util/std_util.h"
-
-namespace cast {
-namespace channel {
-
-using ChannelError = openscreen::Error::Code;
-
-namespace {
-
-static constexpr size_t kHeaderSize = sizeof(uint32_t);
-
-// Cast specifies a max message body size of 64 KiB.
-static constexpr size_t kMaxBodySize = 65536;
-
-} // namespace
-
-class CastFramerTest : public testing::Test {
- public:
- CastFramerTest()
- : buffer_(kHeaderSize + kMaxBodySize),
- framer_(absl::Span<uint8_t>(&buffer_[0], buffer_.size())) {}
-
- void SetUp() override {
- cast_message_.set_protocol_version(CastMessage::CASTV2_1_0);
- cast_message_.set_source_id("source");
- cast_message_.set_destination_id("destination");
- cast_message_.set_namespace_("namespace");
- cast_message_.set_payload_type(CastMessage::STRING);
- cast_message_.set_payload_utf8("payload");
- ErrorOr<std::string> result = MessageFramer::Serialize(cast_message_);
- ASSERT_TRUE(result.is_value());
- cast_message_str_ = std::move(result.value());
- }
-
- void WriteToBuffer(const std::string& data) {
- memcpy(&buffer_[0], data.data(), data.size());
- }
-
- protected:
- CastMessage cast_message_;
- std::string cast_message_str_;
- std::vector<uint8_t> buffer_;
- MessageFramer framer_;
-};
-
-TEST_F(CastFramerTest, TestMessageFramerCompleteMessage) {
- WriteToBuffer(cast_message_str_);
-
- // Receive 1 byte of the header, framer demands 3 more bytes.
- EXPECT_EQ(4u, framer_.BytesRequested().value());
- ErrorOr<CastMessage> result = framer_.TryDeserialize(1);
- EXPECT_FALSE(result);
- EXPECT_EQ(ChannelError::kInsufficientBuffer, result.error().code());
- EXPECT_EQ(3u, framer_.BytesRequested().value());
-
- // TryDeserialize remaining 3, expect that the framer has moved on to
- // requesting the body contents.
- result = framer_.TryDeserialize(3);
- EXPECT_FALSE(result);
- EXPECT_EQ(ChannelError::kInsufficientBuffer, result.error().code());
- EXPECT_EQ(cast_message_str_.size() - kHeaderSize,
- framer_.BytesRequested().value());
-
- // Remainder of packet sent over the wire.
- result = framer_.TryDeserialize(framer_.BytesRequested().value());
- ASSERT_TRUE(result);
- const CastMessage& message = result.value();
- EXPECT_EQ(message.SerializeAsString(), cast_message_.SerializeAsString());
- EXPECT_EQ(4u, framer_.BytesRequested().value());
-}
-
-TEST_F(CastFramerTest, BigEndianMessageHeader) {
- WriteToBuffer(cast_message_str_);
-
- EXPECT_EQ(4u, framer_.BytesRequested().value());
- ErrorOr<CastMessage> result = framer_.TryDeserialize(4);
- EXPECT_FALSE(result);
- EXPECT_EQ(ChannelError::kInsufficientBuffer, result.error().code());
-
- const uint32_t expected_size =
- openscreen::ReadBigEndian<uint32_t>(openscreen::data(cast_message_str_));
- EXPECT_EQ(expected_size, framer_.BytesRequested().value());
-}
-
-TEST_F(CastFramerTest, TestSerializeErrorMessageTooLarge) {
- CastMessage big_message;
- big_message.CopyFrom(cast_message_);
- std::string payload;
- payload.append(kMaxBodySize + 1, 'x');
- big_message.set_payload_utf8(payload);
- EXPECT_FALSE(MessageFramer::Serialize(big_message));
-}
-
-TEST_F(CastFramerTest, TestCompleteMessageAtOnce) {
- WriteToBuffer(cast_message_str_);
-
- ErrorOr<CastMessage> result =
- framer_.TryDeserialize(cast_message_str_.size());
- ASSERT_TRUE(result);
- const CastMessage& message = result.value();
- EXPECT_EQ(message.SerializeAsString(), cast_message_.SerializeAsString());
- EXPECT_EQ(4u, framer_.BytesRequested().value());
-}
-
-TEST_F(CastFramerTest, TestTryDeserializeIllegalLargeMessage) {
- std::string mangled_cast_message = cast_message_str_;
- mangled_cast_message[0] = 88;
- mangled_cast_message[1] = 88;
- mangled_cast_message[2] = 88;
- mangled_cast_message[3] = 88;
- WriteToBuffer(mangled_cast_message);
-
- EXPECT_EQ(4u, framer_.BytesRequested().value());
- ErrorOr<CastMessage> result = framer_.TryDeserialize(4);
- ASSERT_FALSE(result);
- EXPECT_EQ(ChannelError::kCastV2InvalidMessage, result.error().code());
- ErrorOr<size_t> bytes_requested = framer_.BytesRequested();
- ASSERT_FALSE(bytes_requested);
- EXPECT_EQ(ChannelError::kCastV2InvalidMessage,
- bytes_requested.error().code());
-}
-
-TEST_F(CastFramerTest, TestTryDeserializeIllegalLargeMessage2) {
- std::string mangled_cast_message = cast_message_str_;
- // Header indicates body size is 0x00010001 = 65537
- mangled_cast_message[0] = 0;
- mangled_cast_message[1] = 0x1;
- mangled_cast_message[2] = 0;
- mangled_cast_message[3] = 0x1;
- WriteToBuffer(mangled_cast_message);
-
- EXPECT_EQ(4u, framer_.BytesRequested().value());
- ErrorOr<CastMessage> result = framer_.TryDeserialize(4);
- ASSERT_FALSE(result);
- EXPECT_EQ(ChannelError::kCastV2InvalidMessage, result.error().code());
- ErrorOr<size_t> bytes_requested = framer_.BytesRequested();
- ASSERT_FALSE(bytes_requested);
- EXPECT_EQ(ChannelError::kCastV2InvalidMessage,
- bytes_requested.error().code());
-}
-
-TEST_F(CastFramerTest, TestUnparsableBodyProto) {
- // Message header is OK, but the body is replaced with "x"es.
- std::string mangled_cast_message = cast_message_str_;
- for (size_t i = kHeaderSize; i < mangled_cast_message.size(); ++i) {
- std::fill(mangled_cast_message.begin() + kHeaderSize,
- mangled_cast_message.end(), 'x');
- }
- WriteToBuffer(mangled_cast_message);
-
- // Send header.
- EXPECT_EQ(4u, framer_.BytesRequested().value());
- ErrorOr<CastMessage> result = framer_.TryDeserialize(4);
- EXPECT_FALSE(result);
- EXPECT_EQ(ChannelError::kInsufficientBuffer, result.error().code());
- EXPECT_EQ(cast_message_str_.size() - 4, framer_.BytesRequested().value());
-
- // Send body, expect an error.
- result = framer_.TryDeserialize(framer_.BytesRequested().value());
- ASSERT_FALSE(result);
- EXPECT_EQ(ChannelError::kCastV2InvalidMessage, result.error().code());
-}
-
-} // namespace channel
-} // namespace cast
diff --git a/cast/sender/channel/proto/BUILD.gn b/cast/sender/channel/proto/BUILD.gn
deleted file mode 100644
index c3bfa439..00000000
--- a/cast/sender/channel/proto/BUILD.gn
+++ /dev/null
@@ -1,11 +0,0 @@
-# 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.
-
-import("//third_party/protobuf/proto_library.gni")
-
-proto_library("proto") {
- sources = [
- "cast_channel.proto",
- ]
-}
diff --git a/cast/sender/channel/proto/cast_channel.proto b/cast/sender/channel/proto/cast_channel.proto
deleted file mode 100644
index 57c7b3f3..00000000
--- a/cast/sender/channel/proto/cast_channel.proto
+++ /dev/null
@@ -1,99 +0,0 @@
-// 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.
-
-syntax = "proto2";
-
-option optimize_for = LITE_RUNTIME;
-
-package cast.channel;
-
-message CastMessage {
- // Always pass a version of the protocol for future compatibility
- // requirements.
- enum ProtocolVersion { CASTV2_1_0 = 0; }
- required ProtocolVersion protocol_version = 1;
-
- // source and destination ids identify the origin and destination of the
- // message. They are used to route messages between endpoints that share a
- // device-to-device channel.
- //
- // For messages between applications:
- // - The sender application id is a unique identifier generated on behalf of
- // the sender application.
- // - The receiver id is always the the session id for the application.
- //
- // For messages to or from the sender or receiver platform, the special ids
- // 'sender-0' and 'receiver-0' can be used.
- //
- // For messages intended for all endpoints using a given channel, the
- // wildcard destination_id '*' can be used.
- required string source_id = 2;
- required string destination_id = 3;
-
- // This is the core multiplexing key. All messages are sent on a namespace
- // and endpoints sharing a channel listen on one or more namespaces. The
- // namespace defines the protocol and semantics of the message.
- required string namespace = 4;
-
- // Encoding and payload info follows.
-
- // What type of data do we have in this message.
- enum PayloadType {
- STRING = 0;
- BINARY = 1;
- }
- required PayloadType payload_type = 5;
-
- // Depending on payload_type, exactly one of the following optional fields
- // will always be set.
- optional string payload_utf8 = 6;
- optional bytes payload_binary = 7;
-}
-
-enum SignatureAlgorithm {
- UNSPECIFIED = 0;
- RSASSA_PKCS1v15 = 1;
- RSASSA_PSS = 2;
-}
-
-enum HashAlgorithm {
- SHA1 = 0;
- SHA256 = 1;
-}
-
-// Messages for authentication protocol between a sender and a receiver.
-message AuthChallenge {
- optional SignatureAlgorithm signature_algorithm = 1
- [default = RSASSA_PKCS1v15];
- optional bytes sender_nonce = 2;
- optional HashAlgorithm hash_algorithm = 3 [default = SHA1];
-}
-
-message AuthResponse {
- required bytes signature = 1;
- required bytes client_auth_certificate = 2;
- repeated bytes intermediate_certificate = 3;
- optional SignatureAlgorithm signature_algorithm = 4
- [default = RSASSA_PKCS1v15];
- optional bytes sender_nonce = 5;
- optional HashAlgorithm hash_algorithm = 6 [default = SHA1];
- optional bytes crl = 7;
-}
-
-message AuthError {
- enum ErrorType {
- INTERNAL_ERROR = 0;
- NO_TLS = 1; // The underlying connection is not TLS
- SIGNATURE_ALGORITHM_UNAVAILABLE = 2;
- }
- required ErrorType error_type = 1;
-}
-
-message DeviceAuthMessage {
- // Request fields
- optional AuthChallenge challenge = 1;
- // Response fields
- optional AuthResponse response = 2;
- optional AuthError error = 3;
-}