xref: /aosp_15_r20/external/pigweed/pw_transfer/transfer.cc (revision 61c4878ac05f98d0ceed94b57d316916de578985)
1*61c4878aSAndroid Build Coastguard Worker // Copyright 2024 The Pigweed Authors
2*61c4878aSAndroid Build Coastguard Worker //
3*61c4878aSAndroid Build Coastguard Worker // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4*61c4878aSAndroid Build Coastguard Worker // use this file except in compliance with the License. You may obtain a copy of
5*61c4878aSAndroid Build Coastguard Worker // the License at
6*61c4878aSAndroid Build Coastguard Worker //
7*61c4878aSAndroid Build Coastguard Worker //     https://www.apache.org/licenses/LICENSE-2.0
8*61c4878aSAndroid Build Coastguard Worker //
9*61c4878aSAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software
10*61c4878aSAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11*61c4878aSAndroid Build Coastguard Worker // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12*61c4878aSAndroid Build Coastguard Worker // License for the specific language governing permissions and limitations under
13*61c4878aSAndroid Build Coastguard Worker // the License.
14*61c4878aSAndroid Build Coastguard Worker 
15*61c4878aSAndroid Build Coastguard Worker #include <mutex>
16*61c4878aSAndroid Build Coastguard Worker #define PW_LOG_MODULE_NAME "TRN"
17*61c4878aSAndroid Build Coastguard Worker #define PW_LOG_LEVEL PW_TRANSFER_CONFIG_LOG_LEVEL
18*61c4878aSAndroid Build Coastguard Worker 
19*61c4878aSAndroid Build Coastguard Worker #include "public/pw_transfer/transfer.h"
20*61c4878aSAndroid Build Coastguard Worker #include "pw_assert/check.h"
21*61c4878aSAndroid Build Coastguard Worker #include "pw_log/log.h"
22*61c4878aSAndroid Build Coastguard Worker #include "pw_status/try.h"
23*61c4878aSAndroid Build Coastguard Worker #include "pw_transfer/internal/chunk.h"
24*61c4878aSAndroid Build Coastguard Worker #include "pw_transfer/internal/config.h"
25*61c4878aSAndroid Build Coastguard Worker #include "pw_transfer/transfer.h"
26*61c4878aSAndroid Build Coastguard Worker 
27*61c4878aSAndroid Build Coastguard Worker namespace pw::transfer {
28*61c4878aSAndroid Build Coastguard Worker 
HandleChunk(ConstByteSpan message,internal::TransferType type)29*61c4878aSAndroid Build Coastguard Worker void TransferService::HandleChunk(ConstByteSpan message,
30*61c4878aSAndroid Build Coastguard Worker                                   internal::TransferType type) {
31*61c4878aSAndroid Build Coastguard Worker   Result<internal::Chunk> chunk = internal::Chunk::Parse(message);
32*61c4878aSAndroid Build Coastguard Worker   if (!chunk.ok()) {
33*61c4878aSAndroid Build Coastguard Worker     PW_LOG_ERROR("Failed to decode transfer chunk: %d", chunk.status().code());
34*61c4878aSAndroid Build Coastguard Worker     return;
35*61c4878aSAndroid Build Coastguard Worker   }
36*61c4878aSAndroid Build Coastguard Worker 
37*61c4878aSAndroid Build Coastguard Worker   if (chunk->IsInitialChunk()) {
38*61c4878aSAndroid Build Coastguard Worker     uint32_t resource_id =
39*61c4878aSAndroid Build Coastguard Worker         chunk->is_legacy() ? chunk->session_id() : chunk->resource_id().value();
40*61c4878aSAndroid Build Coastguard Worker 
41*61c4878aSAndroid Build Coastguard Worker     uint32_t session_id;
42*61c4878aSAndroid Build Coastguard Worker     if (chunk->is_legacy()) {
43*61c4878aSAndroid Build Coastguard Worker       session_id = chunk->session_id();
44*61c4878aSAndroid Build Coastguard Worker     } else if (chunk->desired_session_id().has_value()) {
45*61c4878aSAndroid Build Coastguard Worker       session_id = chunk->desired_session_id().value();
46*61c4878aSAndroid Build Coastguard Worker     } else {
47*61c4878aSAndroid Build Coastguard Worker       // Non-legacy start chunks are required to use desired_session_id.
48*61c4878aSAndroid Build Coastguard Worker       thread_.SendServerStatus(type,
49*61c4878aSAndroid Build Coastguard Worker                                chunk->session_id(),
50*61c4878aSAndroid Build Coastguard Worker                                chunk->protocol_version(),
51*61c4878aSAndroid Build Coastguard Worker                                Status::DataLoss());
52*61c4878aSAndroid Build Coastguard Worker       return;
53*61c4878aSAndroid Build Coastguard Worker     }
54*61c4878aSAndroid Build Coastguard Worker 
55*61c4878aSAndroid Build Coastguard Worker     uint32_t initial_offset;
56*61c4878aSAndroid Build Coastguard Worker 
57*61c4878aSAndroid Build Coastguard Worker     if (chunk->is_legacy()) {
58*61c4878aSAndroid Build Coastguard Worker       initial_offset = 0;
59*61c4878aSAndroid Build Coastguard Worker     } else {
60*61c4878aSAndroid Build Coastguard Worker       initial_offset = chunk->initial_offset();
61*61c4878aSAndroid Build Coastguard Worker     }
62*61c4878aSAndroid Build Coastguard Worker 
63*61c4878aSAndroid Build Coastguard Worker     thread_.StartServerTransfer(type,
64*61c4878aSAndroid Build Coastguard Worker                                 chunk->protocol_version(),
65*61c4878aSAndroid Build Coastguard Worker                                 session_id,
66*61c4878aSAndroid Build Coastguard Worker                                 resource_id,
67*61c4878aSAndroid Build Coastguard Worker                                 message,
68*61c4878aSAndroid Build Coastguard Worker                                 max_parameters_,
69*61c4878aSAndroid Build Coastguard Worker                                 chunk_timeout_,
70*61c4878aSAndroid Build Coastguard Worker                                 max_retries_,
71*61c4878aSAndroid Build Coastguard Worker                                 max_lifetime_retries_,
72*61c4878aSAndroid Build Coastguard Worker                                 initial_offset);
73*61c4878aSAndroid Build Coastguard Worker   } else {
74*61c4878aSAndroid Build Coastguard Worker     thread_.ProcessServerChunk(message);
75*61c4878aSAndroid Build Coastguard Worker   }
76*61c4878aSAndroid Build Coastguard Worker }
77*61c4878aSAndroid Build Coastguard Worker 
GetResourceStatus(pw::ConstByteSpan request,pw::rpc::RawUnaryResponder & responder)78*61c4878aSAndroid Build Coastguard Worker void TransferService::GetResourceStatus(pw::ConstByteSpan request,
79*61c4878aSAndroid Build Coastguard Worker                                         pw::rpc::RawUnaryResponder& responder) {
80*61c4878aSAndroid Build Coastguard Worker   uint32_t resource_id;
81*61c4878aSAndroid Build Coastguard Worker   Status status;
82*61c4878aSAndroid Build Coastguard Worker   std::array<std::byte, pwpb::ResourceStatus::kMaxEncodedSizeBytes> buffer = {};
83*61c4878aSAndroid Build Coastguard Worker   pwpb::ResourceStatus::MemoryEncoder encoder(buffer);
84*61c4878aSAndroid Build Coastguard Worker 
85*61c4878aSAndroid Build Coastguard Worker   protobuf::Decoder decoder(request);
86*61c4878aSAndroid Build Coastguard Worker   if (status = decoder.Next(); status.IsOutOfRange()) {
87*61c4878aSAndroid Build Coastguard Worker     resource_id = 0;
88*61c4878aSAndroid Build Coastguard Worker   } else if (!status.ok()) {
89*61c4878aSAndroid Build Coastguard Worker     responder.Finish({}, Status::DataLoss()).IgnoreError();
90*61c4878aSAndroid Build Coastguard Worker     return;
91*61c4878aSAndroid Build Coastguard Worker   } else if (static_cast<pwpb::ResourceStatusRequest::Fields>(
92*61c4878aSAndroid Build Coastguard Worker                  decoder.FieldNumber()) ==
93*61c4878aSAndroid Build Coastguard Worker              pwpb::ResourceStatusRequest::Fields::kResourceId) {
94*61c4878aSAndroid Build Coastguard Worker     if (status = decoder.ReadUint32(&resource_id); !status.ok()) {
95*61c4878aSAndroid Build Coastguard Worker       responder.Finish({}, Status::DataLoss()).IgnoreError();
96*61c4878aSAndroid Build Coastguard Worker       return;
97*61c4878aSAndroid Build Coastguard Worker     }
98*61c4878aSAndroid Build Coastguard Worker   } else {
99*61c4878aSAndroid Build Coastguard Worker     responder.Finish({}, Status::DataLoss()).IgnoreError();
100*61c4878aSAndroid Build Coastguard Worker     return;
101*61c4878aSAndroid Build Coastguard Worker   }
102*61c4878aSAndroid Build Coastguard Worker 
103*61c4878aSAndroid Build Coastguard Worker   encoder.WriteResourceId(resource_id).IgnoreError();
104*61c4878aSAndroid Build Coastguard Worker 
105*61c4878aSAndroid Build Coastguard Worker   {
106*61c4878aSAndroid Build Coastguard Worker     std::lock_guard lock(resource_responder_mutex_);
107*61c4878aSAndroid Build Coastguard Worker     if (TransferService::resource_responder_.active()) {
108*61c4878aSAndroid Build Coastguard Worker       PW_LOG_ERROR("Previous GetResourceStatus still being handled!");
109*61c4878aSAndroid Build Coastguard Worker       responder.Finish(ConstByteSpan(encoder), Status::Unavailable())
110*61c4878aSAndroid Build Coastguard Worker           .IgnoreError();
111*61c4878aSAndroid Build Coastguard Worker       return;
112*61c4878aSAndroid Build Coastguard Worker     }
113*61c4878aSAndroid Build Coastguard Worker 
114*61c4878aSAndroid Build Coastguard Worker     TransferService::resource_responder_ = std::move(responder);
115*61c4878aSAndroid Build Coastguard Worker   }
116*61c4878aSAndroid Build Coastguard Worker 
117*61c4878aSAndroid Build Coastguard Worker   thread_.EnqueueResourceEvent(
118*61c4878aSAndroid Build Coastguard Worker       resource_id,
119*61c4878aSAndroid Build Coastguard Worker       [this](Status call_status, const internal::ResourceStatus stats) {
120*61c4878aSAndroid Build Coastguard Worker         this->ResourceStatusCallback(call_status, stats);
121*61c4878aSAndroid Build Coastguard Worker       });
122*61c4878aSAndroid Build Coastguard Worker }
123*61c4878aSAndroid Build Coastguard Worker 
ResourceStatusCallback(Status status,const internal::ResourceStatus & stats)124*61c4878aSAndroid Build Coastguard Worker void TransferService::ResourceStatusCallback(
125*61c4878aSAndroid Build Coastguard Worker     Status status, const internal::ResourceStatus& stats) {
126*61c4878aSAndroid Build Coastguard Worker   std::lock_guard lock(resource_responder_mutex_);
127*61c4878aSAndroid Build Coastguard Worker 
128*61c4878aSAndroid Build Coastguard Worker   if (!resource_responder_.active()) {
129*61c4878aSAndroid Build Coastguard Worker     PW_LOG_ERROR("ResourceStatusCallback invoked without an active responder");
130*61c4878aSAndroid Build Coastguard Worker     return;
131*61c4878aSAndroid Build Coastguard Worker   }
132*61c4878aSAndroid Build Coastguard Worker 
133*61c4878aSAndroid Build Coastguard Worker   std::array<std::byte, pwpb::ResourceStatus::kMaxEncodedSizeBytes> buffer = {};
134*61c4878aSAndroid Build Coastguard Worker   pwpb::ResourceStatus::MemoryEncoder encoder(buffer);
135*61c4878aSAndroid Build Coastguard Worker 
136*61c4878aSAndroid Build Coastguard Worker   encoder.WriteResourceId(stats.resource_id).IgnoreError();
137*61c4878aSAndroid Build Coastguard Worker   encoder.WriteStatus(status.code()).IgnoreError();
138*61c4878aSAndroid Build Coastguard Worker 
139*61c4878aSAndroid Build Coastguard Worker   if (!status.ok()) {
140*61c4878aSAndroid Build Coastguard Worker     resource_responder_.Finish(ConstByteSpan(encoder), status).IgnoreError();
141*61c4878aSAndroid Build Coastguard Worker     return;
142*61c4878aSAndroid Build Coastguard Worker   }
143*61c4878aSAndroid Build Coastguard Worker 
144*61c4878aSAndroid Build Coastguard Worker   encoder.WriteReadableOffset(stats.readable_offset).IgnoreError();
145*61c4878aSAndroid Build Coastguard Worker   encoder.WriteReadChecksum(stats.read_checksum).IgnoreError();
146*61c4878aSAndroid Build Coastguard Worker   encoder.WriteWriteableOffset(stats.writeable_offset).IgnoreError();
147*61c4878aSAndroid Build Coastguard Worker   encoder.WriteWriteChecksum(stats.write_checksum).IgnoreError();
148*61c4878aSAndroid Build Coastguard Worker 
149*61c4878aSAndroid Build Coastguard Worker   if (!encoder.status().ok()) {
150*61c4878aSAndroid Build Coastguard Worker     resource_responder_.Finish(ConstByteSpan(encoder), encoder.status())
151*61c4878aSAndroid Build Coastguard Worker         .IgnoreError();
152*61c4878aSAndroid Build Coastguard Worker     return;
153*61c4878aSAndroid Build Coastguard Worker   }
154*61c4878aSAndroid Build Coastguard Worker 
155*61c4878aSAndroid Build Coastguard Worker   resource_responder_.Finish(ConstByteSpan(encoder), status).IgnoreError();
156*61c4878aSAndroid Build Coastguard Worker }
157*61c4878aSAndroid Build Coastguard Worker 
158*61c4878aSAndroid Build Coastguard Worker }  // namespace pw::transfer
159