rtc_log_file_operations.cc 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235
  1. // Copyright 2020 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "remoting/host/file_transfer/rtc_log_file_operations.h"
  5. #include <algorithm>
  6. #include "base/bind.h"
  7. #include "base/files/file_path.h"
  8. #include "base/memory/raw_ptr.h"
  9. #include "base/memory/weak_ptr.h"
  10. #include "base/notreached.h"
  11. #include "base/strings/stringprintf.h"
  12. #include "base/threading/sequenced_task_runner_handle.h"
  13. #include "base/time/time.h"
  14. #include "remoting/protocol/connection_to_client.h"
  15. #include "remoting/protocol/file_transfer_helpers.h"
  16. #include "remoting/protocol/webrtc_event_log_data.h"
  17. namespace remoting {
  18. namespace {
  19. class RtcLogFileReader : public FileOperations::Reader {
  20. public:
  21. explicit RtcLogFileReader(protocol::ConnectionToClient* connection);
  22. ~RtcLogFileReader() override;
  23. RtcLogFileReader(const RtcLogFileReader&) = delete;
  24. RtcLogFileReader& operator=(const RtcLogFileReader&) = delete;
  25. // FileOperations::Reader interface.
  26. void Open(OpenCallback callback) override;
  27. void ReadChunk(std::size_t size, ReadCallback callback) override;
  28. const base::FilePath& filename() const override;
  29. std::uint64_t size() const override;
  30. FileOperations::State state() const override;
  31. private:
  32. using LogSection = protocol::WebrtcEventLogData::LogSection;
  33. void DoOpen(OpenCallback callback);
  34. void DoReadChunk(std::size_t size, ReadCallback callback);
  35. // Reads up to |maximum_to_read| bytes from the event log, and appends them
  36. // to |output| and returns the number of bytes appended. This only reads from
  37. // a single LogSection, and it takes care of advancing to the next LogSection
  38. // if the end is reached. Returns 0 if there is no more data to be read.
  39. int ReadPartially(int maximum_to_read, std::vector<std::uint8_t>& output);
  40. raw_ptr<protocol::ConnectionToClient> connection_;
  41. base::FilePath filename_;
  42. base::circular_deque<LogSection> data_;
  43. FileOperations::State state_ = FileOperations::kCreated;
  44. // Points to the current LogSection being read from, or data_.end() if
  45. // reading is finished.
  46. base::circular_deque<LogSection>::const_iterator current_log_section_;
  47. // Points to the current read position inside |current_log_section_| or is
  48. // undefined if current_log_section_ == data_.end(). Note that each
  49. // LogSection of |data_| is always non-empty. If the end of a LogSection is
  50. // reached, |current_log_section_| will advance to the next section, and this
  51. // position will be reset to the beginning of the new section.
  52. LogSection::const_iterator current_position_;
  53. base::WeakPtrFactory<RtcLogFileReader> weak_factory_{this};
  54. };
  55. // This class simply returns a protocol error if the client attempts to upload
  56. // a file to this FileOperations implementation. The RTC log is download-only,
  57. // and the upload code-path is never intended to be executed. This class is
  58. // intended to gracefully return an error instead of crashing the host process.
  59. class RtcLogFileWriter : public FileOperations::Writer {
  60. public:
  61. RtcLogFileWriter() = default;
  62. ~RtcLogFileWriter() override = default;
  63. RtcLogFileWriter(const RtcLogFileWriter&) = delete;
  64. RtcLogFileWriter& operator=(const RtcLogFileWriter&) = delete;
  65. // FileOperations::Writer interface.
  66. void Open(const base::FilePath& filename, Callback callback) override;
  67. void WriteChunk(std::vector<std::uint8_t> data, Callback callback) override;
  68. void Close(Callback callback) override;
  69. FileOperations::State state() const override;
  70. };
  71. RtcLogFileReader::RtcLogFileReader(protocol::ConnectionToClient* connection)
  72. : connection_(connection) {}
  73. RtcLogFileReader::~RtcLogFileReader() = default;
  74. void RtcLogFileReader::Open(OpenCallback callback) {
  75. state_ = FileOperations::kBusy;
  76. base::SequencedTaskRunnerHandle::Get()->PostTask(
  77. FROM_HERE,
  78. base::BindOnce(&RtcLogFileReader::DoOpen, weak_factory_.GetWeakPtr(),
  79. std::move(callback)));
  80. }
  81. void RtcLogFileReader::ReadChunk(std::size_t size, ReadCallback callback) {
  82. state_ = FileOperations::kBusy;
  83. base::SequencedTaskRunnerHandle::Get()->PostTask(
  84. FROM_HERE,
  85. base::BindOnce(&RtcLogFileReader::DoReadChunk, weak_factory_.GetWeakPtr(),
  86. size, std::move(callback)));
  87. }
  88. const base::FilePath& RtcLogFileReader::filename() const {
  89. return filename_;
  90. }
  91. std::uint64_t RtcLogFileReader::size() const {
  92. std::uint64_t result = 0;
  93. for (const auto& section : data_) {
  94. result += section.size();
  95. }
  96. return result;
  97. }
  98. FileOperations::State RtcLogFileReader::state() const {
  99. return state_;
  100. }
  101. void RtcLogFileReader::DoOpen(OpenCallback callback) {
  102. protocol::WebrtcEventLogData* rtc_log = connection_->rtc_event_log();
  103. if (!rtc_log) {
  104. // This is a protocol error because RTC log is only supported for WebRTC
  105. // connections.
  106. state_ = FileOperations::kFailed;
  107. std::move(callback).Run(protocol::MakeFileTransferError(
  108. FROM_HERE, protocol::FileTransfer_Error_Type_PROTOCOL_ERROR));
  109. return;
  110. }
  111. base::Time::Exploded exploded;
  112. base::Time::NowFromSystemTime().LocalExplode(&exploded);
  113. std::string filename = base::StringPrintf(
  114. "host-rtc-log-%d-%d-%d_%d-%d-%d", exploded.year, exploded.month,
  115. exploded.day_of_month, exploded.hour, exploded.minute, exploded.second);
  116. filename_ = base::FilePath::FromUTF8Unsafe(filename);
  117. data_ = rtc_log->TakeLogData();
  118. current_log_section_ = data_.begin();
  119. if (!data_.empty()) {
  120. current_position_ = (*current_log_section_).begin();
  121. }
  122. state_ = FileOperations::kReady;
  123. std::move(callback).Run(kSuccessTag);
  124. }
  125. void RtcLogFileReader::DoReadChunk(std::size_t size, ReadCallback callback) {
  126. std::vector<std::uint8_t> result;
  127. int bytes_read;
  128. int bytes_remaining = static_cast<int>(size);
  129. while (bytes_remaining &&
  130. (bytes_read = ReadPartially(bytes_remaining, result)) > 0) {
  131. bytes_remaining -= bytes_read;
  132. }
  133. state_ = result.empty() ? FileOperations::kComplete : FileOperations::kReady;
  134. std::move(callback).Run(result);
  135. }
  136. int RtcLogFileReader::ReadPartially(int maximum_to_read,
  137. std::vector<std::uint8_t>& output) {
  138. if (data_.empty()) {
  139. return 0;
  140. }
  141. if (current_log_section_ == data_.end()) {
  142. return 0;
  143. }
  144. const auto& section = *current_log_section_;
  145. DCHECK(section.begin() <= current_position_);
  146. DCHECK(current_position_ < section.end());
  147. int remaining_in_section = section.end() - current_position_;
  148. int read_amount = std::min(remaining_in_section, maximum_to_read);
  149. output.insert(output.end(), current_position_,
  150. current_position_ + read_amount);
  151. current_position_ += read_amount;
  152. if (current_position_ == section.end()) {
  153. // Advance to beginning of next LogSection.
  154. current_log_section_++;
  155. if (current_log_section_ != data_.end()) {
  156. current_position_ = (*current_log_section_).begin();
  157. }
  158. }
  159. return read_amount;
  160. }
  161. void RtcLogFileWriter::Open(const base::FilePath& filename, Callback callback) {
  162. base::SequencedTaskRunnerHandle::Get()->PostTask(
  163. FROM_HERE,
  164. base::BindOnce(
  165. std::move(callback),
  166. protocol::MakeFileTransferError(
  167. FROM_HERE, protocol::FileTransfer_Error_Type_PROTOCOL_ERROR)));
  168. }
  169. void RtcLogFileWriter::WriteChunk(std::vector<std::uint8_t> data,
  170. Callback callback) {
  171. NOTREACHED();
  172. }
  173. void RtcLogFileWriter::Close(Callback callback) {
  174. NOTREACHED();
  175. }
  176. FileOperations::State RtcLogFileWriter::state() const {
  177. return FileOperations::State::kFailed;
  178. }
  179. } // namespace
  180. RtcLogFileOperations::RtcLogFileOperations(
  181. protocol::ConnectionToClient* connection)
  182. : connection_(connection) {}
  183. RtcLogFileOperations::~RtcLogFileOperations() = default;
  184. std::unique_ptr<FileOperations::Reader> RtcLogFileOperations::CreateReader() {
  185. return std::make_unique<RtcLogFileReader>(connection_);
  186. }
  187. std::unique_ptr<FileOperations::Writer> RtcLogFileOperations::CreateWriter() {
  188. return std::make_unique<RtcLogFileWriter>();
  189. }
  190. } // namespace remoting