xref: /aosp_15_r20/external/pigweed/pw_transfer/public/pw_transfer/transfer.h (revision 61c4878ac05f98d0ceed94b57d316916de578985)
1 // Copyright 2024 The Pigweed Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
5 // the License at
6 //
7 //     https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
13 // the License.
14 #pragma once
15 
16 #include <cstddef>
17 #include <cstdint>
18 #include <limits>
19 
20 #include "pw_bytes/span.h"
21 #include "pw_sync/mutex.h"
22 #include "pw_transfer/handler.h"
23 #include "pw_transfer/internal/config.h"
24 #include "pw_transfer/internal/server_context.h"
25 #include "pw_transfer/transfer.raw_rpc.pb.h"
26 #include "pw_transfer/transfer_thread.h"
27 
28 namespace pw::transfer {
29 namespace internal {
30 
31 class Chunk;
32 
33 }  // namespace internal
34 
35 class TransferService : public pw_rpc::raw::Transfer::Service<TransferService> {
36  public:
37   // Initializes a TransferService that can be registered with an RPC server.
38   //
39   // The transfer service runs all of its transfer tasks on the provided
40   // transfer thread. This thread may be shared between a transfer service and
41   // a transfer client.
42   //
43   // `max_window_size_bytes` is the maximum amount of data to ask for at a
44   // time during a write transfer, unless told a more restrictive amount by a
45   // transfer handler. This size should span multiple chunks, and can be set
46   // quite large. The transfer protocol automatically adjusts its window size
47   // as a transfer progresses to attempt to find an optimal configuration for
48   // the connection over which it is running.
49   TransferService(
50       TransferThread& transfer_thread,
51       uint32_t max_window_size_bytes,
52       chrono::SystemClock::duration chunk_timeout = cfg::kDefaultServerTimeout,
53       uint8_t max_retries = cfg::kDefaultMaxServerRetries,
54       uint32_t extend_window_divisor = cfg::kDefaultExtendWindowDivisor,
55       uint32_t max_lifetime_retries = cfg::kDefaultMaxLifetimeRetries)
56       : max_parameters_(max_window_size_bytes,
57                         transfer_thread.max_chunk_size(),
58                         extend_window_divisor),
59         thread_(transfer_thread),
60         chunk_timeout_(chunk_timeout),
61         max_retries_(max_retries),
62         max_lifetime_retries_(max_lifetime_retries) {}
63 
64   TransferService(const TransferService&) = delete;
65   TransferService(TransferService&&) = delete;
66 
67   TransferService& operator=(const TransferService&) = delete;
68   TransferService& operator=(TransferService&&) = delete;
69 
Read(RawServerReaderWriter & reader_writer)70   void Read(RawServerReaderWriter& reader_writer) {
71     thread_.SetServerReadStream(reader_writer, [this](ConstByteSpan message) {
72       HandleChunk(message, internal::TransferType::kTransmit);
73     });
74   }
75 
Write(RawServerReaderWriter & reader_writer)76   void Write(RawServerReaderWriter& reader_writer) {
77     thread_.SetServerWriteStream(reader_writer, [this](ConstByteSpan message) {
78       HandleChunk(message, internal::TransferType::kReceive);
79     });
80   }
81 
82   void GetResourceStatus(ConstByteSpan request,
83                          rpc::RawUnaryResponder& responder);
84 
RegisterHandler(Handler & handler)85   bool RegisterHandler(Handler& handler) {
86     return thread_.AddTransferHandler(handler);
87   }
88 
UnregisterHandler(Handler & handler)89   bool UnregisterHandler(Handler& handler) {
90     return thread_.RemoveTransferHandler(handler);
91   }
92 
93   [[deprecated("Use set_max_window_size_bytes instead")]]
set_max_pending_bytes(uint32_t pending_bytes)94   constexpr void set_max_pending_bytes(uint32_t pending_bytes) {
95     set_max_window_size_bytes(pending_bytes);
96   }
97 
set_max_window_size_bytes(uint32_t max_window_size_bytes)98   constexpr void set_max_window_size_bytes(uint32_t max_window_size_bytes) {
99     max_parameters_.set_max_window_size_bytes(max_window_size_bytes);
100   }
101 
102   // Sets the maximum size for the data in a pw_transfer chunk. Note that the
103   // max chunk size must always fit within the transfer thread's chunk buffer.
set_max_chunk_size_bytes(uint32_t max_chunk_size_bytes)104   constexpr void set_max_chunk_size_bytes(uint32_t max_chunk_size_bytes) {
105     max_parameters_.set_max_chunk_size_bytes(max_chunk_size_bytes);
106   }
107 
set_chunk_timeout(chrono::SystemClock::duration chunk_timeout)108   constexpr void set_chunk_timeout(
109       chrono::SystemClock::duration chunk_timeout) {
110     chunk_timeout_ = chunk_timeout;
111   }
112 
set_max_retries(uint8_t max_retries)113   constexpr void set_max_retries(uint8_t max_retries) {
114     max_retries_ = max_retries;
115   }
116 
set_extend_window_divisor(uint32_t extend_window_divisor)117   constexpr Status set_extend_window_divisor(uint32_t extend_window_divisor) {
118     if (extend_window_divisor <= 1) {
119       return Status::InvalidArgument();
120     }
121 
122     max_parameters_.set_extend_window_divisor(extend_window_divisor);
123     return OkStatus();
124   }
125 
126  private:
127   void HandleChunk(ConstByteSpan message, internal::TransferType type);
128   void ResourceStatusCallback(Status status,
129                               const internal::ResourceStatus& stats);
130 
131   internal::TransferParameters max_parameters_;
132   TransferThread& thread_;
133 
134   chrono::SystemClock::duration chunk_timeout_;
135   uint8_t max_retries_;
136   uint32_t max_lifetime_retries_;
137 
138   sync::Mutex resource_responder_mutex_;
139   rpc::RawUnaryResponder resource_responder_
140       PW_GUARDED_BY(resource_responder_mutex_);
141 };
142 
143 }  // namespace pw::transfer
144