diff options
author | btolsch <btolsch@chromium.org> | 2019-10-01 11:39:33 -0700 |
---|---|---|
committer | Commit Bot <commit-bot@chromium.org> | 2019-10-01 20:24:53 +0000 |
commit | 9dd4cf87c1214381e72be6b9e1c4af33417e8f99 (patch) | |
tree | 9769ab2c497ed03ff6dac98bec5bfc77434fd36e /cast/sender | |
parent | 5dc91624a6d9d1369769eab8b603399744cdd63c (diff) | |
download | openscreen-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.gn | 10 | ||||
-rw-r--r-- | cast/sender/channel/cast_auth_util.h | 2 | ||||
-rw-r--r-- | cast/sender/channel/cast_auth_util_unittest.cc | 2 | ||||
-rw-r--r-- | cast/sender/channel/cast_framer.cc | 94 | ||||
-rw-r--r-- | cast/sender/channel/cast_framer.h | 59 | ||||
-rw-r--r-- | cast/sender/channel/cast_framer_unittest.cc | 179 | ||||
-rw-r--r-- | cast/sender/channel/proto/BUILD.gn | 11 | ||||
-rw-r--r-- | cast/sender/channel/proto/cast_channel.proto | 99 |
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; -} |