diff --git a/sharing/BUILD b/sharing/BUILD index c7209931..8174e52b 100644 --- a/sharing/BUILD +++ b/sharing/BUILD @@ -199,7 +199,9 @@ cc_library( "//sharing/common:compatible_u8_string", "//sharing/internal/public:logging", "//sharing/internal/public:types", + "//sharing/proto:wire_format_cc_proto", "@com_google_absl//absl/container:flat_hash_map", + "@com_google_absl//absl/strings", "@com_google_absl//absl/strings:string_view", "@com_google_absl//absl/time", "@com_google_absl//absl/types:span", @@ -350,6 +352,17 @@ cc_library( ], ) +cc_library( + name = "attachment_compare", + testonly = True, + srcs = ["attachment_compare.cc"], + hdrs = ["attachment_compare.h"], + deps = [ + ":attachments", + "@com_google_absl//absl/strings", + ], +) + cc_test( name = "advertisement_test", srcs = ["advertisement_test.cc"], @@ -721,6 +734,7 @@ cc_test( name = "attachment_container_test", srcs = ["attachment_container_test.cc"], deps = [ + ":attachment_compare", ":attachments", "@com_github_protobuf_matchers//protobuf-matchers", "@com_google_googletest//:gtest_main", @@ -755,3 +769,22 @@ cc_test( "@com_google_googletest//:gtest_main", ], ) + +cc_test( + name = "incoming_share_target_info_test", + srcs = ["incoming_share_target_info_test.cc"], + deps = [ + ":attachment_compare", + ":attachments", + ":share_target_info", + ":transfer_metadata", + ":types", + "//internal/platform/implementation/g3", # fixdeps: keep + "//sharing/internal/public:logging", + "//sharing/proto:wire_format_cc_proto", + "//third_party/protobuf", + "@com_github_protobuf_matchers//protobuf-matchers", + "@com_google_absl//absl/strings:string_view", + "@com_google_googletest//:gtest_main", + ], +) diff --git a/sharing/attachment_compare.cc b/sharing/attachment_compare.cc new file mode 100644 index 00000000..fd455777 --- /dev/null +++ b/sharing/attachment_compare.cc @@ -0,0 +1,50 @@ +// Copyright 2024 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 "sharing/attachment_compare.h" +#include "sharing/file_attachment.h" +#include "sharing/text_attachment.h" +#include "sharing/wifi_credentials_attachment.h" + +namespace nearby::sharing { + +bool operator==(const TextAttachment& lhs, const TextAttachment& rhs) { + return lhs.id() == rhs.id() && lhs.family() == rhs.family() && + lhs.size() == rhs.size() && lhs.batch_id() == rhs.batch_id() && + lhs.source_type() == rhs.source_type() && lhs.type() == rhs.type() && + lhs.text_title() == rhs.text_title() && + lhs.text_body() == rhs.text_body() && + lhs.mime_type() == rhs.mime_type(); +} + +bool operator==(const FileAttachment& lhs, const FileAttachment& rhs) { + return lhs.id() == rhs.id() && lhs.family() == rhs.family() && + lhs.size() == rhs.size() && lhs.batch_id() == rhs.batch_id() && + lhs.source_type() == rhs.source_type() && + lhs.file_name() == rhs.file_name() && + lhs.mime_type() == rhs.mime_type() && lhs.type() == rhs.type() && + lhs.file_path() == rhs.file_path() && + lhs.parent_folder() == rhs.parent_folder(); +} + +bool operator==(const WifiCredentialsAttachment& lhs, + const WifiCredentialsAttachment& rhs) { + return lhs.id() == rhs.id() && lhs.family() == rhs.family() && + lhs.size() == rhs.size() && lhs.batch_id() == rhs.batch_id() && + lhs.ssid() == rhs.ssid() && + lhs.security_type() == rhs.security_type() && + lhs.password() == rhs.password() && lhs.is_hidden() == rhs.is_hidden(); +} + +} // namespace nearby::sharing diff --git a/sharing/attachment_compare.h b/sharing/attachment_compare.h new file mode 100644 index 00000000..1a098ce5 --- /dev/null +++ b/sharing/attachment_compare.h @@ -0,0 +1,31 @@ +// Copyright 2024 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. + +#ifndef THIRD_PARTY_NEARBY_SHARING_ATTACHMENT_COMPARE_H_ +#define THIRD_PARTY_NEARBY_SHARING_ATTACHMENT_COMPARE_H_ + +#include "sharing/file_attachment.h" +#include "sharing/text_attachment.h" +#include "sharing/wifi_credentials_attachment.h" + +namespace nearby::sharing { + +bool operator==(const TextAttachment& lhs, const TextAttachment& rhs); +bool operator==(const FileAttachment& lhs, const FileAttachment& rhs); +bool operator==(const WifiCredentialsAttachment& lhs, + const WifiCredentialsAttachment& rhs); + +} // namespace nearby::sharing + +#endif // THIRD_PARTY_NEARBY_SHARING_ATTACHMENT_COMPARE_H_ diff --git a/sharing/attachment_container.cc b/sharing/attachment_container.cc index 74e9ff23..8a96838f 100644 --- a/sharing/attachment_container.cc +++ b/sharing/attachment_container.cc @@ -50,6 +50,17 @@ int64_t AttachmentContainer::GetTotalAttachmentsSize() const { return size_in_bytes; } +int64_t AttachmentContainer::GetStorageSize() const { + int64_t size_in_bytes = 0; + + // Only files require disk storage. + for (const auto& file : file_attachments_) { + size_in_bytes += file.size(); + } + + return size_in_bytes; +} + void AttachmentContainer::ClearAttachments() { // Reset file paths for file attachments. for (auto& file : file_attachments_) @@ -66,6 +77,12 @@ void AttachmentContainer::ClearAttachments() { } } +void AttachmentContainer::Clear() { + file_attachments_.clear(); + text_attachments_.clear(); + wifi_credentials_attachments_.clear(); +} + std::vector AttachmentContainer::GetAttachmentIds() const { std::vector attachment_ids; diff --git a/sharing/attachment_container.h b/sharing/attachment_container.h index 7a0d2896..61f59aaa 100644 --- a/sharing/attachment_container.h +++ b/sharing/attachment_container.h @@ -83,6 +83,9 @@ class AttachmentContainer { // Returns the total size of all attachments. int64_t GetTotalAttachmentsSize() const; + // Returns the total size of all attachments on disk. + int64_t GetStorageSize() const; + // Returns true if there are any attachments. bool HasAttachments() const { return !text_attachments_.empty() || !file_attachments_.empty() || @@ -93,6 +96,9 @@ class AttachmentContainer { // place. void ClearAttachments(); + // Delete all attachments. + void Clear(); + // Returns the list of attachment IDs of attachments in this container. std::vector GetAttachmentIds() const; diff --git a/sharing/attachment_container_test.cc b/sharing/attachment_container_test.cc index e3c7a147..4a3027a9 100644 --- a/sharing/attachment_container_test.cc +++ b/sharing/attachment_container_test.cc @@ -23,40 +23,12 @@ #include "protobuf-matchers/protocol-buffer-matchers.h" #include "gtest/gtest.h" #include "sharing/attachment.h" +#include "sharing/attachment_compare.h" // IWYU pragma: keep #include "sharing/file_attachment.h" #include "sharing/text_attachment.h" #include "sharing/wifi_credentials_attachment.h" namespace nearby::sharing { - -bool operator==(const TextAttachment& lhs, const TextAttachment& rhs) { - return lhs.id() == rhs.id() && lhs.family() == rhs.family() && - lhs.size() == rhs.size() && lhs.batch_id() == rhs.batch_id() && - lhs.source_type() == rhs.source_type() && lhs.type() == rhs.type() && - lhs.text_title() == rhs.text_title() && - lhs.text_body() == rhs.text_body() && - lhs.mime_type() == rhs.mime_type(); -} - -bool operator==(const FileAttachment& lhs, const FileAttachment& rhs) { - return lhs.id() == rhs.id() && lhs.family() == rhs.family() && - lhs.size() == rhs.size() && lhs.batch_id() == rhs.batch_id() && - lhs.source_type() == rhs.source_type() && - lhs.file_name() == rhs.file_name() && - lhs.mime_type() == rhs.mime_type() && lhs.type() == rhs.type() && - lhs.file_path() == rhs.file_path() && - lhs.parent_folder() == rhs.parent_folder(); -} - -bool operator==(const WifiCredentialsAttachment& lhs, - const WifiCredentialsAttachment& rhs) { - return lhs.id() == rhs.id() && lhs.family() == rhs.family() && - lhs.size() == rhs.size() && lhs.batch_id() == rhs.batch_id() && - lhs.ssid() == rhs.ssid() && - lhs.security_type() == rhs.security_type() && - lhs.password() == rhs.password() && lhs.is_hidden() == rhs.is_hidden(); -} - namespace { using testing::Eq; @@ -209,6 +181,17 @@ TEST_F(AttachmentContainerTest, ClearAttachments) { IsFalse()); } +TEST_F(AttachmentContainerTest, Clear) { + AttachmentContainer container(std::vector{text1_, text2_}, + std::vector{file1_}, + std::vector{wifi1_}); + EXPECT_THAT(container.HasAttachments(), IsTrue()); + + container.Clear(); + + EXPECT_THAT(container.HasAttachments(), IsFalse()); +} + TEST_F(AttachmentContainerTest, GetAttachmentIds) { AttachmentContainer container(std::vector{text1_, text2_}, std::vector{file1_}, @@ -222,6 +205,16 @@ TEST_F(AttachmentContainerTest, GetAttachmentIds) { wifi1_.id())); } +TEST_F(AttachmentContainerTest, GetStorageSize) { + AttachmentContainer container(std::vector{text1_, text2_}, + std::vector{file1_}, + std::vector{wifi1_}); + + int64_t storage_size = container.GetStorageSize(); + + EXPECT_THAT(storage_size, Eq(file1_.size())); +} + } // namespace } // namespace nearby::sharing diff --git a/sharing/incoming_share_target_info.cc b/sharing/incoming_share_target_info.cc index 6c8f2067..a69e0fd6 100644 --- a/sharing/incoming_share_target_info.cc +++ b/sharing/incoming_share_target_info.cc @@ -14,17 +14,31 @@ #include "sharing/incoming_share_target_info.h" +#include #include +#include +#include #include #include +#include "sharing/attachment_container.h" +#include "sharing/constants.h" +#include "sharing/file_attachment.h" +#include "sharing/internal/public/logging.h" #include "sharing/nearby_connection.h" +#include "sharing/proto/wire_format.pb.h" #include "sharing/share_target.h" #include "sharing/share_target_info.h" +#include "sharing/text_attachment.h" #include "sharing/transfer_metadata.h" +#include "sharing/wifi_credentials_attachment.h" -namespace nearby { -namespace sharing { +namespace nearby::sharing { +namespace { + +using ::nearby::sharing::service::proto::IntroductionFrame; + +} // namespace IncomingShareTargetInfo::IncomingShareTargetInfo( std::string endpoint_id, const ShareTarget& share_target, @@ -52,5 +66,77 @@ bool IncomingShareTargetInfo::OnNewConnection(NearbyConnection* connection) { return true; } -} // namespace sharing -} // namespace nearby +std::optional +IncomingShareTargetInfo::ProcessIntroduction( + const IntroductionFrame& introduction_frame) { + int64_t file_size_sum = 0; + AttachmentContainer& container = mutable_attachment_container(); + for (const auto& file : introduction_frame.file_metadata()) { + if (file.size() <= 0) { + NL_LOG(WARNING) + << __func__ + << ": Ignore introduction, due to invalid attachment size"; + return TransferMetadata::Status::kUnsupportedAttachmentType; + } + + NL_VLOG(1) << __func__ << ": Found file attachment: id=" << file.id() + << ", type= " << file.type() << ", size=" << file.size() + << ", payload_id=" << file.payload_id() + << ", parent_folder=" << file.parent_folder() + << ", mime_type=" << file.mime_type(); + container.AddFileAttachment( + FileAttachment(file.id(), file.size(), file.name(), file.mime_type(), + file.type(), file.parent_folder())); + SetAttachmentPayloadId(file.id(), file.payload_id()); + + if (std::numeric_limits::max() - file.size() < file_size_sum) { + NL_LOG(WARNING) << __func__ + << ": Ignoring introduction, total file size overflowed " + "64 bit integer."; + container.Clear(); + return TransferMetadata::Status::kNotEnoughSpace; + } + file_size_sum += file.size(); + } + + for (const auto& text : introduction_frame.text_metadata()) { + if (text.size() <= 0) { + NL_LOG(WARNING) + << __func__ + << ": Ignore introduction, due to invalid attachment size"; + return TransferMetadata::Status::kUnsupportedAttachmentType; + } + + NL_VLOG(1) << __func__ << ": Found text attachment: id=" << text.id() + << ", type= " << text.type() << ", size=" << text.size() + << ", payload_id=" << text.payload_id(); + container.AddTextAttachment( + TextAttachment(text.id(), text.type(), text.text_title(), text.size())); + SetAttachmentPayloadId(text.id(), text.payload_id()); + } + + if (kSupportReceivingWifiCredentials) { + for (const auto& wifi_credentials : + introduction_frame.wifi_credentials_metadata()) { + NL_VLOG(1) << __func__ << ": Found WiFi credentials attachment: id=" + << wifi_credentials.id() + << ", ssid= " << wifi_credentials.ssid() + << ", payload_id=" << wifi_credentials.payload_id(); + container.AddWifiCredentialsAttachment(WifiCredentialsAttachment( + wifi_credentials.id(), wifi_credentials.ssid(), + wifi_credentials.security_type())); + SetAttachmentPayloadId(wifi_credentials.id(), + wifi_credentials.payload_id()); + } + } + + if (!container.HasAttachments()) { + NL_LOG(WARNING) << __func__ + << ": No attachment is found for this share target. It can " + "be result of unrecognizable attachment type"; + return TransferMetadata::Status::kUnsupportedAttachmentType; + } + return std::nullopt; +} + +} // namespace nearby::sharing diff --git a/sharing/incoming_share_target_info.h b/sharing/incoming_share_target_info.h index 941b1b80..2d871a3f 100644 --- a/sharing/incoming_share_target_info.h +++ b/sharing/incoming_share_target_info.h @@ -16,14 +16,15 @@ #define THIRD_PARTY_NEARBY_SHARING_INCOMING_SHARE_TARGET_INFO_H_ #include +#include #include #include "sharing/nearby_connection.h" +#include "sharing/proto/wire_format.pb.h" #include "sharing/share_target.h" #include "sharing/share_target_info.h" #include "sharing/transfer_metadata.h" -namespace nearby { -namespace sharing { +namespace nearby::sharing { class IncomingShareTargetInfo : public ShareTargetInfo { public: @@ -38,6 +39,13 @@ class IncomingShareTargetInfo : public ShareTargetInfo { bool IsIncoming() const override { return true; } + // Returns nullopt on success. + // On failure, returns the status that should be used to terminate the + // connection. + std::optional ProcessIntroduction( + const nearby::sharing::service::proto::IntroductionFrame& + introduction_frame); + protected: void InvokeTransferUpdateCallback(const TransferMetadata& metadata) override; bool OnNewConnection(NearbyConnection* connection) override; @@ -47,7 +55,6 @@ class IncomingShareTargetInfo : public ShareTargetInfo { transfer_update_callback_; }; -} // namespace sharing -} // namespace nearby +} // namespace nearby::sharing #endif // THIRD_PARTY_NEARBY_SHARING_INCOMING_SHARE_TARGET_INFO_H_ diff --git a/sharing/incoming_share_target_info_test.cc b/sharing/incoming_share_target_info_test.cc new file mode 100644 index 00000000..313aa5f1 --- /dev/null +++ b/sharing/incoming_share_target_info_test.cc @@ -0,0 +1,197 @@ +// Copyright 2024 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 "sharing/incoming_share_target_info.h" + +#include +#include +#include +#include +#include + +#include "gmock/gmock.h" +#include "protobuf-matchers/protocol-buffer-matchers.h" +#include "gtest/gtest.h" +#include "absl/strings/string_view.h" +#include "sharing/attachment_compare.h" // IWYU pragma: keep +#include "sharing/file_attachment.h" +#include "sharing/internal/public/logging.h" +#include "sharing/proto/wire_format.pb.h" +#include "sharing/share_target.h" +#include "sharing/text_attachment.h" +#include "sharing/transfer_metadata.h" +#include "sharing/wifi_credentials_attachment.h" +#include "google/protobuf/text_format.h" + +namespace nearby::sharing { +namespace { + +using ::nearby::sharing::service::proto::FileMetadata; +using ::nearby::sharing::service::proto::IntroductionFrame; +using ::nearby::sharing::service::proto::TextMetadata; +using ::nearby::sharing::service::proto::WifiCredentialsMetadata; +using ::testing::Eq; +using ::testing::IsFalse; +using ::testing::IsTrue; +using ::testing::UnorderedElementsAre; + +constexpr absl::string_view kEndpointId = "ABCD"; + +class IncomingShareTargetInfoTest : public ::testing::Test { + protected: + IncomingShareTargetInfoTest() + : info_(std::string(kEndpointId), share_target_, + [](const IncomingShareTargetInfo&, const TransferMetadata&) {}) { + NL_CHECK( + proto2::TextFormat::ParseFromString(R"pb( + file_metadata { + id: 1234 + size: 100 + name: "file_name1" + mime_type: "application/pdf" + type: DOCUMENT + parent_folder: "parent_folder1" + payload_id: 9876 + } + file_metadata { + id: 1235 + size: 200 + name: "file_name2" + mime_type: "image/jpeg" + type: IMAGE + parent_folder: "parent_folder2" + payload_id: 9875 + } + text_metadata { + id: 1236 + size: 300 + text_title: "text_title1" + type: URL + payload_id: 9874 + } + text_metadata { + id: 1237 + size: 400 + text_title: "text_title2" + type: TEXT + payload_id: 9873 + } + wifi_credentials_metadata { + id: 1238 + ssid: "ssid1" + security_type: WPA_PSK + payload_id: 9872 + } + wifi_credentials_metadata { + id: 1239 + ssid: "ssid2" + security_type: WEP + payload_id: 9871 + } + )pb", + &introduction_frame_)); + } + + ShareTarget share_target_; + IncomingShareTargetInfo info_; + IntroductionFrame introduction_frame_; +}; + +TEST_F(IncomingShareTargetInfoTest, ProcessIntroductionNoSupportedPayload) { + IntroductionFrame frame; + + EXPECT_THAT(info_.ProcessIntroduction(frame), + Eq(TransferMetadata::Status::kUnsupportedAttachmentType)); + EXPECT_THAT(info_.attachment_container().HasAttachments(), IsFalse()); +} + +TEST_F(IncomingShareTargetInfoTest, ProcessIntroductionEmptyFile) { + IntroductionFrame frame; + frame.mutable_file_metadata(); + + EXPECT_THAT(info_.ProcessIntroduction(frame), + Eq(TransferMetadata::Status::kUnsupportedAttachmentType)); + EXPECT_THAT(info_.attachment_container().HasAttachments(), IsFalse()); +} + +TEST_F(IncomingShareTargetInfoTest, ProcessIntroductionFilesTooLarge) { + IntroductionFrame frame; + FileMetadata file1; + FileMetadata file2; + file1.set_size(std::numeric_limits::max()); + file2.set_size(1); + frame.mutable_file_metadata()->Add(std::move(file1)); + frame.mutable_file_metadata()->Add(std::move(file2)); + + EXPECT_THAT(info_.ProcessIntroduction(frame), + Eq(TransferMetadata::Status::kNotEnoughSpace)); + EXPECT_THAT(info_.attachment_container().HasAttachments(), IsFalse()); +} + +TEST_F(IncomingShareTargetInfoTest, ProcessIntroductionEmptyText) { + IntroductionFrame frame; + frame.mutable_text_metadata(); + + EXPECT_THAT(info_.ProcessIntroduction(frame), + Eq(TransferMetadata::Status::kUnsupportedAttachmentType)); + EXPECT_THAT(info_.attachment_container().HasAttachments(), IsFalse()); +} + +TEST_F(IncomingShareTargetInfoTest, ProcessIntroductionSuccess) { + FileMetadata filemeta1 = introduction_frame_.file_metadata(0); + FileAttachment file1(filemeta1.id(), filemeta1.size(), filemeta1.name(), + filemeta1.mime_type(), filemeta1.type(), + filemeta1.parent_folder()); + FileMetadata filemeta2 = introduction_frame_.file_metadata(1); + FileAttachment file2(filemeta2.id(), filemeta2.size(), filemeta2.name(), + filemeta2.mime_type(), filemeta2.type(), + filemeta2.parent_folder()); + TextMetadata textmeta1 = introduction_frame_.text_metadata(0); + TextAttachment text1(textmeta1.id(), textmeta1.type(), textmeta1.text_title(), + textmeta1.size()); + TextMetadata textmeta2 = introduction_frame_.text_metadata(1); + TextAttachment text2(textmeta2.id(), textmeta2.type(), textmeta2.text_title(), + textmeta2.size()); + WifiCredentialsMetadata wifimeta1 = + introduction_frame_.wifi_credentials_metadata(0); + WifiCredentialsAttachment wifi1(wifimeta1.id(), wifimeta1.ssid(), + wifimeta1.security_type()); + WifiCredentialsMetadata wifimeta2 = + introduction_frame_.wifi_credentials_metadata(1); + WifiCredentialsAttachment wifi2(wifimeta2.id(), wifimeta2.ssid(), + wifimeta2.security_type()); + + EXPECT_THAT(info_.ProcessIntroduction(introduction_frame_), Eq(std::nullopt)); + EXPECT_THAT(info_.attachment_container().HasAttachments(), IsTrue()); + EXPECT_THAT(info_.attachment_container().GetFileAttachments(), + UnorderedElementsAre(file1, file2)); + EXPECT_THAT(info_.attachment_container().GetTextAttachments(), + UnorderedElementsAre(text1, text2)); + EXPECT_THAT(info_.attachment_container().GetWifiCredentialsAttachments(), + UnorderedElementsAre(wifi1, wifi2)); + EXPECT_THAT(info_.attachment_payload_map().at(filemeta1.id()).payload_id, + Eq(filemeta1.payload_id())); + EXPECT_THAT(info_.attachment_payload_map().at(filemeta2.id()).payload_id, + Eq(filemeta2.payload_id())); + EXPECT_THAT(info_.attachment_payload_map().at(textmeta1.id()).payload_id, + Eq(textmeta1.payload_id())); + EXPECT_THAT(info_.attachment_payload_map().at(textmeta2.id()).payload_id, + Eq(textmeta2.payload_id())); + EXPECT_THAT(info_.attachment_payload_map().at(wifimeta1.id()).payload_id, + Eq(wifimeta1.payload_id())); + EXPECT_THAT(info_.attachment_payload_map().at(wifimeta2.id()).payload_id, + Eq(wifimeta2.payload_id())); +} +} // namespace +} // namespace nearby::sharing diff --git a/sharing/nearby_sharing_service_impl.cc b/sharing/nearby_sharing_service_impl.cc index bfc284a6..b7a72b42 100644 --- a/sharing/nearby_sharing_service_impl.cc +++ b/sharing/nearby_sharing_service_impl.cc @@ -22,7 +22,6 @@ #include // NOLINT(build/c++17) #include #include -#include #include #include #include @@ -38,7 +37,6 @@ #include "absl/functional/bind_front.h" #include "absl/random/random.h" #include "absl/status/statusor.h" -#include "absl/strings/str_cat.h" #include "absl/strings/string_view.h" #include "absl/time/time.h" #include "absl/types/span.h" @@ -55,7 +53,6 @@ #include "sharing/advertisement.h" #include "sharing/analytics/analytics_information.h" #include "sharing/analytics/analytics_recorder.h" -#include "sharing/attachment.h" #include "sharing/attachment_container.h" #include "sharing/attachment_info.h" #include "sharing/certificates/common.h" @@ -2728,72 +2725,18 @@ void NearbySharingServiceImpl::SendIntroduction( } // Build the introduction. - auto introduction = - std::make_unique(); - introduction->set_start_transfer(true); - NL_VLOG(1) << __func__ << ": Sending attachments to " - << info.share_target().id; - - const AttachmentContainer& container = info.attachment_container(); - // Write introduction of file payloads. - for (const auto& file : container.GetFileAttachments()) { - std::optional payload_id = GetAttachmentPayloadId(file.id()); - if (!payload_id) { - NL_VLOG(1) << __func__ << ": Skipping unknown file attachment"; - continue; - } - auto* file_metadata = introduction->add_file_metadata(); - file_metadata->set_id(file.id()); - file_metadata->set_name(absl::StrCat(file.file_name())); - file_metadata->set_payload_id(*payload_id); - file_metadata->set_type(file.type()); - file_metadata->set_mime_type(absl::StrCat(file.mime_type())); - file_metadata->set_size(file.size()); - } - - // Write introduction of text payloads. - for (const auto& text : container.GetTextAttachments()) { - std::optional payload_id = GetAttachmentPayloadId(text.id()); - if (!payload_id) { - NL_VLOG(1) << __func__ << ": Skipping unknown text attachment"; - continue; - } - auto* text_metadata = introduction->add_text_metadata(); - text_metadata->set_id(text.id()); - text_metadata->set_text_title(std::string(text.text_title())); - text_metadata->set_type(text.type()); - text_metadata->set_size(text.size()); - text_metadata->set_payload_id(*payload_id); - } - - // Write introduction of Wi-Fi credentials payloads. - for (const auto& wifi_credentials : - container.GetWifiCredentialsAttachments()) { - std::optional payload_id = - GetAttachmentPayloadId(wifi_credentials.id()); - if (!payload_id) { - NL_VLOG(1) << __func__ - << ": Skipping unknown WiFi credentials attachment"; - continue; - } - auto* wifi_credentials_metadata = - introduction->add_wifi_credentials_metadata(); - wifi_credentials_metadata->set_id(wifi_credentials.id()); - wifi_credentials_metadata->set_ssid(std::string(wifi_credentials.ssid())); - wifi_credentials_metadata->set_security_type( - wifi_credentials.security_type()); - wifi_credentials_metadata->set_payload_id(*payload_id); - } - - if (introduction->file_metadata_size() == 0 && - introduction->text_metadata_size() == 0 && - introduction->wifi_credentials_metadata_size() == 0) { + std::unique_ptr + introduction = info.CreateIntroductionFrame(); + if (!introduction) { NL_LOG(WARNING) << __func__ << ": No payloads tied to transfer, disconnecting."; AbortAndCloseConnectionIfNecessary( TransferMetadata::Status::kMissingPayloads, info.share_target().id); return; } + introduction->set_start_transfer(true); + NL_VLOG(1) << __func__ << ": Sending attachments to " + << info.share_target().id; // Write the introduction to the remote device. nearby::sharing::service::proto::Frame frame; @@ -3429,109 +3372,27 @@ void NearbySharingServiceImpl::OnReceivedIntroduction( NL_LOG(INFO) << __func__ << ": Successfully read the introduction frame."; - int64_t file_size_sum = 0; - - nearby::sharing::service::proto::IntroductionFrame introduction_frame = - std::move(frame->introduction()); - - AttachmentContainer& container = info->mutable_attachment_container(); - for (const auto& file : introduction_frame.file_metadata()) { - if (file.size() <= 0) { - Fail(share_target_id, - TransferMetadata::Status::kUnsupportedAttachmentType); - NL_LOG(WARNING) - << __func__ - << ": Ignore introduction, due to invalid attachment size"; - return; - } - - NL_VLOG(1) << __func__ << ": Found file attachment: id=" << file.id() - << ", type= " << file.type() << ", size=" << file.size() - << ", payload_id=" << file.payload_id() - << ", parent_folder=" << file.parent_folder() - << ", mime_type=" << file.mime_type(); - FileAttachment attachment(file.id(), file.size(), file.name(), - file.mime_type(), file.type(), - file.parent_folder()); - SetAttachmentPayloadId(attachment, file.payload_id()); - container.AddFileAttachment(std::move(attachment)); - - if (std::numeric_limits::max() - file.size() < file_size_sum) { - Fail(share_target_id, TransferMetadata::Status::kNotEnoughSpace); - NL_LOG(WARNING) << __func__ - << ": Ignoring introduction, total file size overflowed " - "64 bit integer."; - return; - } - file_size_sum += file.size(); - } - - for (const auto& text : introduction_frame.text_metadata()) { - if (text.size() <= 0) { - Fail(share_target_id, - TransferMetadata::Status::kUnsupportedAttachmentType); - NL_LOG(WARNING) - << __func__ - << ": Ignore introduction, due to invalid attachment size"; - return; - } - - NL_VLOG(1) << __func__ << ": Found text attachment: id=" << text.id() - << ", type= " << text.type() << ", size=" << text.size() - << ", payload_id=" << text.payload_id(); - TextAttachment attachment(text.id(), text.type(), text.text_title(), - text.size()); - SetAttachmentPayloadId(attachment, text.payload_id()); - container.AddTextAttachment(std::move(attachment)); - } - - if (kSupportReceivingWifiCredentials) { - for (const auto& wifi_credentials : - introduction_frame.wifi_credentials_metadata()) { - NL_VLOG(1) << __func__ << ": Found WiFi credentials attachment: id=" - << wifi_credentials.id() - << ", ssid= " << wifi_credentials.ssid() - << ", payload_id=" << wifi_credentials.payload_id(); - WifiCredentialsAttachment attachment(wifi_credentials.id(), - wifi_credentials.ssid(), - wifi_credentials.security_type()); - SetAttachmentPayloadId(attachment, wifi_credentials.payload_id()); - container.AddWifiCredentialsAttachment(std::move(attachment)); - } - } - - if (!container.HasAttachments()) { - NL_LOG(WARNING) << __func__ - << ": No attachment is found for this share target. It can " - "be result of unrecognizable attachment type"; - Fail(share_target_id, TransferMetadata::Status::kUnsupportedAttachmentType); - - NL_VLOG(1) << __func__ - << ": We don't support the attachments sent by the sender. " - "We have informed " - << share_target_id; + std::optional status = + info->ProcessIntroduction(frame->introduction()); + if (status.has_value()) { + Fail(share_target_id, *status); return; } + attachment_info_map_ = info->attachment_payload_map(); // Log analytics event of receiving introduction. analytics_recorder_->NewReceiveIntroduction( receiving_session_id_, info->share_target(), /*referrer_package=*/std::nullopt, info->os_type()); - if (file_size_sum == 0) { - OnStorageCheckCompleted(share_target_id, std::move(four_digit_token), - /*is_out_of_storage=*/false); - return; - } - // Controls BWU using a flag when receiving an introduction frame, since it // could be a problem before accepted by a user. if (!NearbyFlags::GetInstance().GetBoolFlag( sharing::config_package_nearby::nearby_sharing_feature:: kUpgradeBandwidthAfterAccept)) { - if (introduction_frame.has_start_transfer() && - introduction_frame.start_transfer()) { - if (container.GetTotalAttachmentsSize() >= + if (frame->introduction().has_start_transfer() && + frame->introduction().start_transfer()) { + if (info->attachment_container().GetTotalAttachmentsSize() >= kAttachmentsSizeThresholdOverHighQualityMedium) { NL_LOG(INFO) << __func__ @@ -3545,7 +3406,8 @@ void NearbySharingServiceImpl::OnReceivedIntroduction( std::filesystem::u8path(settings_->GetCustomSavePath()); bool is_out_of_storage = - IsOutOfStorage(device_info_, download_path, file_size_sum); + IsOutOfStorage(device_info_, download_path, + info->attachment_container().GetStorageSize()); OnStorageCheckCompleted(share_target_id, std::move(four_digit_token), is_out_of_storage); @@ -4322,11 +4184,6 @@ void NearbySharingServiceImpl::ClearOutgoingShareTargetInfoMap() { NL_DCHECK(outgoing_share_target_info_map_.empty()); } -void NearbySharingServiceImpl::SetAttachmentPayloadId( - const Attachment& attachment, int64_t payload_id) { - attachment_info_map_[attachment.id()].payload_id = payload_id; -} - std::optional NearbySharingServiceImpl::GetAttachmentPayloadId( int64_t attachment_id) { auto it = attachment_info_map_.find(attachment_id); diff --git a/sharing/nearby_sharing_service_impl.h b/sharing/nearby_sharing_service_impl.h index 92c091b6..b7a11321 100644 --- a/sharing/nearby_sharing_service_impl.h +++ b/sharing/nearby_sharing_service_impl.h @@ -44,7 +44,6 @@ #include "proto/sharing_enums.pb.h" #include "sharing/advertisement.h" #include "sharing/analytics/analytics_recorder.h" -#include "sharing/attachment.h" #include "sharing/attachment_container.h" #include "sharing/attachment_info.h" #include "sharing/certificates/nearby_share_certificate_manager.h" @@ -426,7 +425,6 @@ class NearbySharingServiceImpl OutgoingShareTargetInfo& info); void ClearOutgoingShareTargetInfoMap(); - void SetAttachmentPayloadId(const Attachment& attachment, int64_t payload_id); std::optional GetAttachmentPayloadId(int64_t attachment_id); void UnregisterShareTarget(int64_t share_target_id); diff --git a/sharing/outgoing_share_target_info.cc b/sharing/outgoing_share_target_info.cc index a5339c3a..4063f975 100644 --- a/sharing/outgoing_share_target_info.cc +++ b/sharing/outgoing_share_target_info.cc @@ -18,6 +18,7 @@ #include #include // NOLINT #include +#include #include #include #include @@ -153,6 +154,64 @@ bool OutgoingShareTargetInfo::CreateFilePayloads( return true; } +std::unique_ptr +OutgoingShareTargetInfo::CreateIntroductionFrame() const { + const AttachmentContainer& container = attachment_container(); + if (!container.HasAttachments()) { + return nullptr; + } + if (file_payloads_.size() != container.GetFileAttachments().size() || + text_payloads_.size() != container.GetTextAttachments().size() || + wifi_credentials_payloads_.size() != + container.GetWifiCredentialsAttachments().size()) { + return nullptr; + } + auto introduction = + std::make_unique(); + // Write introduction of file payloads. + const std::vector& file_attachments = + container.GetFileAttachments(); + for (int i = 0; i < file_attachments.size(); ++i) { + const FileAttachment& file = file_attachments[i]; + auto* file_metadata = introduction->add_file_metadata(); + file_metadata->set_id(file.id()); + file_metadata->set_name(std::string(file.file_name())); + file_metadata->set_payload_id(file_payloads_[i].id); + file_metadata->set_type(file.type()); + file_metadata->set_mime_type(std::string(file.mime_type())); + file_metadata->set_size(file.size()); + } + + // Write introduction of text payloads. + const std::vector& text_attachments = + container.GetTextAttachments(); + for (int i = 0; i < text_attachments.size(); ++i) { + const TextAttachment& text = text_attachments[i]; + auto* text_metadata = introduction->add_text_metadata(); + text_metadata->set_id(text.id()); + text_metadata->set_text_title(std::string(text.text_title())); + text_metadata->set_type(text.type()); + text_metadata->set_size(text.size()); + text_metadata->set_payload_id(text_payloads_[i].id); + } + + // Write introduction of Wi-Fi credentials payloads. + const std::vector& wifi_credentials_attachments = + container.GetWifiCredentialsAttachments(); + for (int i = 0; i < wifi_credentials_attachments.size(); ++i) { + const WifiCredentialsAttachment& wifi_credentials = + wifi_credentials_attachments[i]; + auto* wifi_credentials_metadata = + introduction->add_wifi_credentials_metadata(); + wifi_credentials_metadata->set_id(wifi_credentials.id()); + wifi_credentials_metadata->set_ssid(std::string(wifi_credentials.ssid())); + wifi_credentials_metadata->set_security_type( + wifi_credentials.security_type()); + wifi_credentials_metadata->set_payload_id(wifi_credentials_payloads_[i].id); + } + return introduction; +} + std::vector OutgoingShareTargetInfo::ExtractTextPayloads() { return std::move(text_payloads_); } diff --git a/sharing/outgoing_share_target_info.h b/sharing/outgoing_share_target_info.h index 938a5c87..c45ce2f5 100644 --- a/sharing/outgoing_share_target_info.h +++ b/sharing/outgoing_share_target_info.h @@ -17,6 +17,7 @@ #include // NOLINT #include +#include #include #include #include @@ -78,6 +79,9 @@ class OutgoingShareTargetInfo : public ShareTargetInfo { bool CreateFilePayloads( const std::vector& files); + std::unique_ptr + CreateIntroductionFrame() const; + std::vector ExtractTextPayloads(); std::vector ExtractFilePayloads(); std::vector ExtractWifiCredentialsPayloads(); diff --git a/sharing/outgoing_share_target_info_test.cc b/sharing/outgoing_share_target_info_test.cc index ea60491b..b5608441 100644 --- a/sharing/outgoing_share_target_info_test.cc +++ b/sharing/outgoing_share_target_info_test.cc @@ -15,6 +15,7 @@ #include "sharing/outgoing_share_target_info.h" #include +#include #include #include #include @@ -35,6 +36,7 @@ namespace nearby::sharing { namespace { +using ::nearby::sharing::service::proto::IntroductionFrame; using ::nearby::sharing::service::proto::WifiCredentials; using ::testing::Eq; using ::testing::IsEmpty; @@ -213,5 +215,55 @@ TEST_F(OutgoingShareTargetInfoTest, CreateWifiCredentialsPayloads) { EXPECT_THAT(attachment_payload_map.at(wifi1_.id()).payload_id.value(), Eq(payloads[0].id)); } + +TEST_F(OutgoingShareTargetInfoTest, CreateIntroductionFrameWithoutPayloads) { + EXPECT_THAT(info_.CreateIntroductionFrame(), Eq(nullptr)); +} + +TEST_F(OutgoingShareTargetInfoTest, CreateIntroductionFrameSuccess) { + std::vector file_infos; + file_infos.push_back({ + .size = 12355L, + .file_path = file1_.file_path().value(), + }); + info_.CreateFilePayloads(file_infos); + info_.CreateTextPayloads(); + info_.CreateWifiCredentialsPayloads(); + std::unique_ptr frame = info_.CreateIntroductionFrame(); + + const std::vector& text_payloads = info_.text_payloads(); + ASSERT_THAT(frame->text_metadata_size(), Eq(2)); + EXPECT_THAT(frame->text_metadata(0).id(), Eq(text1_.id())); + EXPECT_THAT(frame->text_metadata(0).text_title(), Eq(text1_.text_title())); + EXPECT_THAT(frame->text_metadata(0).type(), Eq(text1_.type())); + EXPECT_THAT(frame->text_metadata(0).size(), Eq(text1_.size())); + EXPECT_THAT(frame->text_metadata(0).payload_id(), Eq(text_payloads[0].id)); + + EXPECT_THAT(frame->text_metadata(1).id(), Eq(text2_.id())); + EXPECT_THAT(frame->text_metadata(1).text_title(), Eq(text2_.text_title())); + EXPECT_THAT(frame->text_metadata(1).type(), Eq(text2_.type())); + EXPECT_THAT(frame->text_metadata(1).size(), Eq(text2_.size())); + EXPECT_THAT(frame->text_metadata(1).payload_id(), Eq(text_payloads[1].id)); + + const std::vector& file_payloads = info_.file_payloads(); + ASSERT_THAT(frame->file_metadata_size(), Eq(1)); + EXPECT_THAT(frame->file_metadata(0).id(), Eq(file1_.id())); + // File attachment size has been updated by CreateFilePayloads(). + EXPECT_THAT(frame->file_metadata(0).size(), Eq(file_infos[0].size)); + EXPECT_THAT(frame->file_metadata(0).name(), Eq(file1_.file_name())); + EXPECT_THAT(frame->file_metadata(0).payload_id(), Eq(file_payloads[0].id)); + EXPECT_THAT(frame->file_metadata(0).type(), Eq(file1_.type())); + EXPECT_THAT(frame->file_metadata(0).mime_type(), Eq(file1_.mime_type())); + + const std::vector& wifi_payloads = info_.wifi_credentials_payloads(); + ASSERT_THAT(frame->wifi_credentials_metadata_size(), Eq(1)); + EXPECT_THAT(frame->wifi_credentials_metadata(0).id(), Eq(wifi1_.id())); + EXPECT_THAT(frame->wifi_credentials_metadata(0).ssid(), Eq(wifi1_.ssid())); + EXPECT_THAT(frame->wifi_credentials_metadata(0).security_type(), + Eq(wifi1_.security_type())); + EXPECT_THAT(frame->wifi_credentials_metadata(0).payload_id(), + Eq(wifi_payloads[0].id)); +} + } // namespace } // namespace nearby::sharing