xref: /aosp_15_r20/system/core/fastboot/udp.cpp (revision 00c7fec1bb09f3284aad6a6f96d2f63dfc3650ad)
1*00c7fec1SAndroid Build Coastguard Worker /*
2*00c7fec1SAndroid Build Coastguard Worker  * Copyright (C) 2015 The Android Open Source Project
3*00c7fec1SAndroid Build Coastguard Worker  * All rights reserved.
4*00c7fec1SAndroid Build Coastguard Worker  *
5*00c7fec1SAndroid Build Coastguard Worker  * Redistribution and use in source and binary forms, with or without
6*00c7fec1SAndroid Build Coastguard Worker  * modification, are permitted provided that the following conditions
7*00c7fec1SAndroid Build Coastguard Worker  * are met:
8*00c7fec1SAndroid Build Coastguard Worker  *  * Redistributions of source code must retain the above copyright
9*00c7fec1SAndroid Build Coastguard Worker  *    notice, this list of conditions and the following disclaimer.
10*00c7fec1SAndroid Build Coastguard Worker  *  * Redistributions in binary form must reproduce the above copyright
11*00c7fec1SAndroid Build Coastguard Worker  *    notice, this list of conditions and the following disclaimer in
12*00c7fec1SAndroid Build Coastguard Worker  *    the documentation and/or other materials provided with the
13*00c7fec1SAndroid Build Coastguard Worker  *    distribution.
14*00c7fec1SAndroid Build Coastguard Worker  *
15*00c7fec1SAndroid Build Coastguard Worker  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16*00c7fec1SAndroid Build Coastguard Worker  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17*00c7fec1SAndroid Build Coastguard Worker  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
18*00c7fec1SAndroid Build Coastguard Worker  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
19*00c7fec1SAndroid Build Coastguard Worker  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
20*00c7fec1SAndroid Build Coastguard Worker  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21*00c7fec1SAndroid Build Coastguard Worker  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
22*00c7fec1SAndroid Build Coastguard Worker  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
23*00c7fec1SAndroid Build Coastguard Worker  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24*00c7fec1SAndroid Build Coastguard Worker  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
25*00c7fec1SAndroid Build Coastguard Worker  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26*00c7fec1SAndroid Build Coastguard Worker  * SUCH DAMAGE.
27*00c7fec1SAndroid Build Coastguard Worker  */
28*00c7fec1SAndroid Build Coastguard Worker 
29*00c7fec1SAndroid Build Coastguard Worker // This file implements the fastboot UDP protocol; see fastboot_protocol.txt for documentation.
30*00c7fec1SAndroid Build Coastguard Worker 
31*00c7fec1SAndroid Build Coastguard Worker #include "udp.h"
32*00c7fec1SAndroid Build Coastguard Worker 
33*00c7fec1SAndroid Build Coastguard Worker #include <errno.h>
34*00c7fec1SAndroid Build Coastguard Worker #include <stdio.h>
35*00c7fec1SAndroid Build Coastguard Worker 
36*00c7fec1SAndroid Build Coastguard Worker #include <list>
37*00c7fec1SAndroid Build Coastguard Worker #include <memory>
38*00c7fec1SAndroid Build Coastguard Worker #include <vector>
39*00c7fec1SAndroid Build Coastguard Worker 
40*00c7fec1SAndroid Build Coastguard Worker #include <android-base/macros.h>
41*00c7fec1SAndroid Build Coastguard Worker #include <android-base/stringprintf.h>
42*00c7fec1SAndroid Build Coastguard Worker 
43*00c7fec1SAndroid Build Coastguard Worker #include "socket.h"
44*00c7fec1SAndroid Build Coastguard Worker 
45*00c7fec1SAndroid Build Coastguard Worker namespace udp {
46*00c7fec1SAndroid Build Coastguard Worker 
47*00c7fec1SAndroid Build Coastguard Worker using namespace internal;
48*00c7fec1SAndroid Build Coastguard Worker 
49*00c7fec1SAndroid Build Coastguard Worker constexpr size_t kMinPacketSize = 512;
50*00c7fec1SAndroid Build Coastguard Worker constexpr size_t kHeaderSize = 4;
51*00c7fec1SAndroid Build Coastguard Worker 
52*00c7fec1SAndroid Build Coastguard Worker enum Index {
53*00c7fec1SAndroid Build Coastguard Worker     kIndexId = 0,
54*00c7fec1SAndroid Build Coastguard Worker     kIndexFlags = 1,
55*00c7fec1SAndroid Build Coastguard Worker     kIndexSeqH = 2,
56*00c7fec1SAndroid Build Coastguard Worker     kIndexSeqL = 3,
57*00c7fec1SAndroid Build Coastguard Worker };
58*00c7fec1SAndroid Build Coastguard Worker 
59*00c7fec1SAndroid Build Coastguard Worker // Extracts a big-endian uint16_t from a byte array.
ExtractUint16(const uint8_t * bytes)60*00c7fec1SAndroid Build Coastguard Worker static uint16_t ExtractUint16(const uint8_t* bytes) {
61*00c7fec1SAndroid Build Coastguard Worker     return (static_cast<uint16_t>(bytes[0]) << 8) | bytes[1];
62*00c7fec1SAndroid Build Coastguard Worker }
63*00c7fec1SAndroid Build Coastguard Worker 
64*00c7fec1SAndroid Build Coastguard Worker // Packet header handling.
65*00c7fec1SAndroid Build Coastguard Worker class Header {
66*00c7fec1SAndroid Build Coastguard Worker   public:
67*00c7fec1SAndroid Build Coastguard Worker     Header();
68*00c7fec1SAndroid Build Coastguard Worker     ~Header() = default;
69*00c7fec1SAndroid Build Coastguard Worker 
id() const70*00c7fec1SAndroid Build Coastguard Worker     uint8_t id() const { return bytes_[kIndexId]; }
bytes() const71*00c7fec1SAndroid Build Coastguard Worker     const uint8_t* bytes() const { return bytes_; }
72*00c7fec1SAndroid Build Coastguard Worker 
73*00c7fec1SAndroid Build Coastguard Worker     void Set(uint8_t id, uint16_t sequence, Flag flag);
74*00c7fec1SAndroid Build Coastguard Worker 
75*00c7fec1SAndroid Build Coastguard Worker     // Checks whether |response| is a match for this header.
76*00c7fec1SAndroid Build Coastguard Worker     bool Matches(const uint8_t* response);
77*00c7fec1SAndroid Build Coastguard Worker 
78*00c7fec1SAndroid Build Coastguard Worker   private:
79*00c7fec1SAndroid Build Coastguard Worker     uint8_t bytes_[kHeaderSize];
80*00c7fec1SAndroid Build Coastguard Worker };
81*00c7fec1SAndroid Build Coastguard Worker 
Header()82*00c7fec1SAndroid Build Coastguard Worker Header::Header() {
83*00c7fec1SAndroid Build Coastguard Worker     Set(kIdError, 0, kFlagNone);
84*00c7fec1SAndroid Build Coastguard Worker }
85*00c7fec1SAndroid Build Coastguard Worker 
Set(uint8_t id,uint16_t sequence,Flag flag)86*00c7fec1SAndroid Build Coastguard Worker void Header::Set(uint8_t id, uint16_t sequence, Flag flag) {
87*00c7fec1SAndroid Build Coastguard Worker     bytes_[kIndexId] = id;
88*00c7fec1SAndroid Build Coastguard Worker     bytes_[kIndexFlags] = flag;
89*00c7fec1SAndroid Build Coastguard Worker     bytes_[kIndexSeqH] = sequence >> 8;
90*00c7fec1SAndroid Build Coastguard Worker     bytes_[kIndexSeqL] = sequence;
91*00c7fec1SAndroid Build Coastguard Worker }
92*00c7fec1SAndroid Build Coastguard Worker 
Matches(const uint8_t * response)93*00c7fec1SAndroid Build Coastguard Worker bool Header::Matches(const uint8_t* response) {
94*00c7fec1SAndroid Build Coastguard Worker     // Sequence numbers must be the same to match, but the response ID can either be the same
95*00c7fec1SAndroid Build Coastguard Worker     // or an error response which is always accepted.
96*00c7fec1SAndroid Build Coastguard Worker     return bytes_[kIndexSeqH] == response[kIndexSeqH] &&
97*00c7fec1SAndroid Build Coastguard Worker            bytes_[kIndexSeqL] == response[kIndexSeqL] &&
98*00c7fec1SAndroid Build Coastguard Worker            (bytes_[kIndexId] == response[kIndexId] || response[kIndexId] == kIdError);
99*00c7fec1SAndroid Build Coastguard Worker }
100*00c7fec1SAndroid Build Coastguard Worker 
101*00c7fec1SAndroid Build Coastguard Worker // Implements the Transport interface to work with the fastboot engine.
102*00c7fec1SAndroid Build Coastguard Worker class UdpTransport : public Transport {
103*00c7fec1SAndroid Build Coastguard Worker   public:
104*00c7fec1SAndroid Build Coastguard Worker     // Factory function so we can return nullptr if initialization fails.
105*00c7fec1SAndroid Build Coastguard Worker     static std::unique_ptr<UdpTransport> NewTransport(std::unique_ptr<Socket> socket,
106*00c7fec1SAndroid Build Coastguard Worker                                                       std::string* error);
107*00c7fec1SAndroid Build Coastguard Worker     ~UdpTransport() override = default;
108*00c7fec1SAndroid Build Coastguard Worker 
109*00c7fec1SAndroid Build Coastguard Worker     ssize_t Read(void* data, size_t length) override;
110*00c7fec1SAndroid Build Coastguard Worker     ssize_t Write(const void* data, size_t length) override;
111*00c7fec1SAndroid Build Coastguard Worker     int Close() override;
112*00c7fec1SAndroid Build Coastguard Worker     int Reset() override;
113*00c7fec1SAndroid Build Coastguard Worker 
114*00c7fec1SAndroid Build Coastguard Worker   private:
UdpTransport(std::unique_ptr<Socket> socket)115*00c7fec1SAndroid Build Coastguard Worker     explicit UdpTransport(std::unique_ptr<Socket> socket) : socket_(std::move(socket)) {}
116*00c7fec1SAndroid Build Coastguard Worker 
117*00c7fec1SAndroid Build Coastguard Worker     // Performs the UDP initialization procedure. Returns true on success.
118*00c7fec1SAndroid Build Coastguard Worker     bool InitializeProtocol(std::string* error);
119*00c7fec1SAndroid Build Coastguard Worker 
120*00c7fec1SAndroid Build Coastguard Worker     // Sends |length| bytes from |data| and waits for the response packet up to |attempts| times.
121*00c7fec1SAndroid Build Coastguard Worker     // Continuation packets are handled automatically and any return data is written to |rx_data|.
122*00c7fec1SAndroid Build Coastguard Worker     // Excess bytes that cannot fit in |rx_data| are dropped.
123*00c7fec1SAndroid Build Coastguard Worker     // On success, returns the number of response data bytes received, which may be greater than
124*00c7fec1SAndroid Build Coastguard Worker     // |rx_length|. On failure, returns -1 and fills |error| on failure.
125*00c7fec1SAndroid Build Coastguard Worker     ssize_t SendData(Id id, const uint8_t* tx_data, size_t tx_length, uint8_t* rx_data,
126*00c7fec1SAndroid Build Coastguard Worker                      size_t rx_length, int attempts, std::string* error);
127*00c7fec1SAndroid Build Coastguard Worker 
128*00c7fec1SAndroid Build Coastguard Worker     // Helper for SendData(); sends a single packet and handles the response. |header| specifies
129*00c7fec1SAndroid Build Coastguard Worker     // the initial outgoing packet information but may be modified by this function.
130*00c7fec1SAndroid Build Coastguard Worker     ssize_t SendSinglePacketHelper(Header* header, const uint8_t* tx_data, size_t tx_length,
131*00c7fec1SAndroid Build Coastguard Worker                                    uint8_t* rx_data, size_t rx_length, int attempts,
132*00c7fec1SAndroid Build Coastguard Worker                                    std::string* error);
133*00c7fec1SAndroid Build Coastguard Worker 
134*00c7fec1SAndroid Build Coastguard Worker     std::unique_ptr<Socket> socket_;
135*00c7fec1SAndroid Build Coastguard Worker     int sequence_ = -1;
136*00c7fec1SAndroid Build Coastguard Worker     size_t max_data_length_ = kMinPacketSize - kHeaderSize;
137*00c7fec1SAndroid Build Coastguard Worker     std::vector<uint8_t> rx_packet_;
138*00c7fec1SAndroid Build Coastguard Worker 
139*00c7fec1SAndroid Build Coastguard Worker     DISALLOW_COPY_AND_ASSIGN(UdpTransport);
140*00c7fec1SAndroid Build Coastguard Worker };
141*00c7fec1SAndroid Build Coastguard Worker 
NewTransport(std::unique_ptr<Socket> socket,std::string * error)142*00c7fec1SAndroid Build Coastguard Worker std::unique_ptr<UdpTransport> UdpTransport::NewTransport(std::unique_ptr<Socket> socket,
143*00c7fec1SAndroid Build Coastguard Worker                                                          std::string* error) {
144*00c7fec1SAndroid Build Coastguard Worker     std::unique_ptr<UdpTransport> transport(new UdpTransport(std::move(socket)));
145*00c7fec1SAndroid Build Coastguard Worker 
146*00c7fec1SAndroid Build Coastguard Worker     if (!transport->InitializeProtocol(error)) {
147*00c7fec1SAndroid Build Coastguard Worker         return nullptr;
148*00c7fec1SAndroid Build Coastguard Worker     }
149*00c7fec1SAndroid Build Coastguard Worker 
150*00c7fec1SAndroid Build Coastguard Worker     return transport;
151*00c7fec1SAndroid Build Coastguard Worker }
152*00c7fec1SAndroid Build Coastguard Worker 
InitializeProtocol(std::string * error)153*00c7fec1SAndroid Build Coastguard Worker bool UdpTransport::InitializeProtocol(std::string* error) {
154*00c7fec1SAndroid Build Coastguard Worker     uint8_t rx_data[4];
155*00c7fec1SAndroid Build Coastguard Worker 
156*00c7fec1SAndroid Build Coastguard Worker     sequence_ = 0;
157*00c7fec1SAndroid Build Coastguard Worker     rx_packet_.resize(kMinPacketSize);
158*00c7fec1SAndroid Build Coastguard Worker 
159*00c7fec1SAndroid Build Coastguard Worker     // First send the query packet to sync with the target. Only attempt this a small number of
160*00c7fec1SAndroid Build Coastguard Worker     // times so we can fail out quickly if the target isn't available.
161*00c7fec1SAndroid Build Coastguard Worker     ssize_t rx_bytes = SendData(kIdDeviceQuery, nullptr, 0, rx_data, sizeof(rx_data),
162*00c7fec1SAndroid Build Coastguard Worker                                 kMaxConnectAttempts, error);
163*00c7fec1SAndroid Build Coastguard Worker     if (rx_bytes == -1) {
164*00c7fec1SAndroid Build Coastguard Worker         return false;
165*00c7fec1SAndroid Build Coastguard Worker     } else if (rx_bytes < 2) {
166*00c7fec1SAndroid Build Coastguard Worker         *error = "invalid query response from target";
167*00c7fec1SAndroid Build Coastguard Worker         return false;
168*00c7fec1SAndroid Build Coastguard Worker     }
169*00c7fec1SAndroid Build Coastguard Worker     // The first two bytes contain the next expected sequence number.
170*00c7fec1SAndroid Build Coastguard Worker     sequence_ = ExtractUint16(rx_data);
171*00c7fec1SAndroid Build Coastguard Worker 
172*00c7fec1SAndroid Build Coastguard Worker     // Now send the initialization packet with our version and maximum packet size.
173*00c7fec1SAndroid Build Coastguard Worker     uint8_t init_data[] = {kProtocolVersion >> 8, kProtocolVersion & 0xFF,
174*00c7fec1SAndroid Build Coastguard Worker                            kHostMaxPacketSize >> 8, kHostMaxPacketSize & 0xFF};
175*00c7fec1SAndroid Build Coastguard Worker     rx_bytes = SendData(kIdInitialization, init_data, sizeof(init_data), rx_data, sizeof(rx_data),
176*00c7fec1SAndroid Build Coastguard Worker                         kMaxTransmissionAttempts, error);
177*00c7fec1SAndroid Build Coastguard Worker     if (rx_bytes == -1) {
178*00c7fec1SAndroid Build Coastguard Worker         return false;
179*00c7fec1SAndroid Build Coastguard Worker     } else if (rx_bytes < 4) {
180*00c7fec1SAndroid Build Coastguard Worker         *error = "invalid initialization response from target";
181*00c7fec1SAndroid Build Coastguard Worker         return false;
182*00c7fec1SAndroid Build Coastguard Worker     }
183*00c7fec1SAndroid Build Coastguard Worker 
184*00c7fec1SAndroid Build Coastguard Worker     // The first two data bytes contain the version, the second two bytes contain the target max
185*00c7fec1SAndroid Build Coastguard Worker     // supported packet size, which must be at least 512 bytes.
186*00c7fec1SAndroid Build Coastguard Worker     uint16_t version = ExtractUint16(rx_data);
187*00c7fec1SAndroid Build Coastguard Worker     if (version < kProtocolVersion) {
188*00c7fec1SAndroid Build Coastguard Worker         *error = android::base::StringPrintf("target reported invalid protocol version %d",
189*00c7fec1SAndroid Build Coastguard Worker                                              version);
190*00c7fec1SAndroid Build Coastguard Worker         return false;
191*00c7fec1SAndroid Build Coastguard Worker     }
192*00c7fec1SAndroid Build Coastguard Worker     uint16_t packet_size = ExtractUint16(rx_data + 2);
193*00c7fec1SAndroid Build Coastguard Worker     if (packet_size < kMinPacketSize) {
194*00c7fec1SAndroid Build Coastguard Worker         *error = android::base::StringPrintf("target reported invalid packet size %d", packet_size);
195*00c7fec1SAndroid Build Coastguard Worker         return false;
196*00c7fec1SAndroid Build Coastguard Worker     }
197*00c7fec1SAndroid Build Coastguard Worker 
198*00c7fec1SAndroid Build Coastguard Worker     packet_size = std::min(kHostMaxPacketSize, packet_size);
199*00c7fec1SAndroid Build Coastguard Worker     max_data_length_ = packet_size - kHeaderSize;
200*00c7fec1SAndroid Build Coastguard Worker     rx_packet_.resize(packet_size);
201*00c7fec1SAndroid Build Coastguard Worker 
202*00c7fec1SAndroid Build Coastguard Worker     return true;
203*00c7fec1SAndroid Build Coastguard Worker }
204*00c7fec1SAndroid Build Coastguard Worker 
205*00c7fec1SAndroid Build Coastguard Worker // SendData() is just responsible for chunking |data| into packets until it's all been sent.
206*00c7fec1SAndroid Build Coastguard Worker // Per-packet timeout/retransmission logic is done in SendSinglePacketHelper().
SendData(Id id,const uint8_t * tx_data,size_t tx_length,uint8_t * rx_data,size_t rx_length,int attempts,std::string * error)207*00c7fec1SAndroid Build Coastguard Worker ssize_t UdpTransport::SendData(Id id, const uint8_t* tx_data, size_t tx_length, uint8_t* rx_data,
208*00c7fec1SAndroid Build Coastguard Worker                                size_t rx_length, int attempts, std::string* error) {
209*00c7fec1SAndroid Build Coastguard Worker     if (socket_ == nullptr) {
210*00c7fec1SAndroid Build Coastguard Worker         *error = "socket is closed";
211*00c7fec1SAndroid Build Coastguard Worker         return -1;
212*00c7fec1SAndroid Build Coastguard Worker     }
213*00c7fec1SAndroid Build Coastguard Worker 
214*00c7fec1SAndroid Build Coastguard Worker     Header header;
215*00c7fec1SAndroid Build Coastguard Worker     size_t packet_data_length;
216*00c7fec1SAndroid Build Coastguard Worker     ssize_t ret = 0;
217*00c7fec1SAndroid Build Coastguard Worker     // We often send header-only packets with no data as part of the protocol, so always send at
218*00c7fec1SAndroid Build Coastguard Worker     // least once even if |length| == 0, then repeat until we've sent all of |data|.
219*00c7fec1SAndroid Build Coastguard Worker     do {
220*00c7fec1SAndroid Build Coastguard Worker         // Set the continuation flag and truncate packet data if needed.
221*00c7fec1SAndroid Build Coastguard Worker         if (tx_length > max_data_length_) {
222*00c7fec1SAndroid Build Coastguard Worker             packet_data_length = max_data_length_;
223*00c7fec1SAndroid Build Coastguard Worker             header.Set(id, sequence_, kFlagContinuation);
224*00c7fec1SAndroid Build Coastguard Worker         } else {
225*00c7fec1SAndroid Build Coastguard Worker             packet_data_length = tx_length;
226*00c7fec1SAndroid Build Coastguard Worker             header.Set(id, sequence_, kFlagNone);
227*00c7fec1SAndroid Build Coastguard Worker         }
228*00c7fec1SAndroid Build Coastguard Worker 
229*00c7fec1SAndroid Build Coastguard Worker         ssize_t bytes = SendSinglePacketHelper(&header, tx_data, packet_data_length, rx_data,
230*00c7fec1SAndroid Build Coastguard Worker                                                rx_length, attempts, error);
231*00c7fec1SAndroid Build Coastguard Worker 
232*00c7fec1SAndroid Build Coastguard Worker         // Advance our read and write buffers for the next packet. Keep going even if we run out
233*00c7fec1SAndroid Build Coastguard Worker         // of receive buffer space so we can detect overflows.
234*00c7fec1SAndroid Build Coastguard Worker         if (bytes == -1) {
235*00c7fec1SAndroid Build Coastguard Worker             return -1;
236*00c7fec1SAndroid Build Coastguard Worker         } else if (static_cast<size_t>(bytes) < rx_length) {
237*00c7fec1SAndroid Build Coastguard Worker             rx_data += bytes;
238*00c7fec1SAndroid Build Coastguard Worker             rx_length -= bytes;
239*00c7fec1SAndroid Build Coastguard Worker         } else {
240*00c7fec1SAndroid Build Coastguard Worker             rx_data = nullptr;
241*00c7fec1SAndroid Build Coastguard Worker             rx_length = 0;
242*00c7fec1SAndroid Build Coastguard Worker         }
243*00c7fec1SAndroid Build Coastguard Worker 
244*00c7fec1SAndroid Build Coastguard Worker         tx_length -= packet_data_length;
245*00c7fec1SAndroid Build Coastguard Worker         tx_data += packet_data_length;
246*00c7fec1SAndroid Build Coastguard Worker 
247*00c7fec1SAndroid Build Coastguard Worker         ret += bytes;
248*00c7fec1SAndroid Build Coastguard Worker     } while (tx_length > 0);
249*00c7fec1SAndroid Build Coastguard Worker 
250*00c7fec1SAndroid Build Coastguard Worker     return ret;
251*00c7fec1SAndroid Build Coastguard Worker }
252*00c7fec1SAndroid Build Coastguard Worker 
SendSinglePacketHelper(Header * header,const uint8_t * tx_data,size_t tx_length,uint8_t * rx_data,size_t rx_length,const int attempts,std::string * error)253*00c7fec1SAndroid Build Coastguard Worker ssize_t UdpTransport::SendSinglePacketHelper(
254*00c7fec1SAndroid Build Coastguard Worker         Header* header, const uint8_t* tx_data, size_t tx_length, uint8_t* rx_data,
255*00c7fec1SAndroid Build Coastguard Worker         size_t rx_length, const int attempts, std::string* error) {
256*00c7fec1SAndroid Build Coastguard Worker     ssize_t total_data_bytes = 0;
257*00c7fec1SAndroid Build Coastguard Worker     error->clear();
258*00c7fec1SAndroid Build Coastguard Worker 
259*00c7fec1SAndroid Build Coastguard Worker     int attempts_left = attempts;
260*00c7fec1SAndroid Build Coastguard Worker     while (attempts_left > 0) {
261*00c7fec1SAndroid Build Coastguard Worker         if (!socket_->Send({{header->bytes(), kHeaderSize}, {tx_data, tx_length}})) {
262*00c7fec1SAndroid Build Coastguard Worker             *error = Socket::GetErrorMessage();
263*00c7fec1SAndroid Build Coastguard Worker             return -1;
264*00c7fec1SAndroid Build Coastguard Worker         }
265*00c7fec1SAndroid Build Coastguard Worker 
266*00c7fec1SAndroid Build Coastguard Worker         // Keep receiving until we get a matching response or we timeout.
267*00c7fec1SAndroid Build Coastguard Worker         ssize_t bytes = 0;
268*00c7fec1SAndroid Build Coastguard Worker         do {
269*00c7fec1SAndroid Build Coastguard Worker             bytes = socket_->Receive(rx_packet_.data(), rx_packet_.size(), kResponseTimeoutMs);
270*00c7fec1SAndroid Build Coastguard Worker             if (bytes == -1) {
271*00c7fec1SAndroid Build Coastguard Worker                 if (socket_->ReceiveTimedOut()) {
272*00c7fec1SAndroid Build Coastguard Worker                     break;
273*00c7fec1SAndroid Build Coastguard Worker                 }
274*00c7fec1SAndroid Build Coastguard Worker                 *error = Socket::GetErrorMessage();
275*00c7fec1SAndroid Build Coastguard Worker                 return -1;
276*00c7fec1SAndroid Build Coastguard Worker             } else if (bytes < static_cast<ssize_t>(kHeaderSize)) {
277*00c7fec1SAndroid Build Coastguard Worker                 *error = "protocol error: incomplete header";
278*00c7fec1SAndroid Build Coastguard Worker                 return -1;
279*00c7fec1SAndroid Build Coastguard Worker             }
280*00c7fec1SAndroid Build Coastguard Worker         } while (!header->Matches(rx_packet_.data()));
281*00c7fec1SAndroid Build Coastguard Worker 
282*00c7fec1SAndroid Build Coastguard Worker         if (socket_->ReceiveTimedOut()) {
283*00c7fec1SAndroid Build Coastguard Worker             --attempts_left;
284*00c7fec1SAndroid Build Coastguard Worker             continue;
285*00c7fec1SAndroid Build Coastguard Worker         }
286*00c7fec1SAndroid Build Coastguard Worker         ++sequence_;
287*00c7fec1SAndroid Build Coastguard Worker 
288*00c7fec1SAndroid Build Coastguard Worker         // Save to |error| or |rx_data| as appropriate.
289*00c7fec1SAndroid Build Coastguard Worker         if (rx_packet_[kIndexId] == kIdError) {
290*00c7fec1SAndroid Build Coastguard Worker             error->append(rx_packet_.data() + kHeaderSize, rx_packet_.data() + bytes);
291*00c7fec1SAndroid Build Coastguard Worker         } else {
292*00c7fec1SAndroid Build Coastguard Worker             total_data_bytes += bytes - kHeaderSize;
293*00c7fec1SAndroid Build Coastguard Worker             size_t rx_data_bytes = std::min<size_t>(bytes - kHeaderSize, rx_length);
294*00c7fec1SAndroid Build Coastguard Worker             if (rx_data_bytes > 0) {
295*00c7fec1SAndroid Build Coastguard Worker                 memcpy(rx_data, rx_packet_.data() + kHeaderSize, rx_data_bytes);
296*00c7fec1SAndroid Build Coastguard Worker                 rx_data += rx_data_bytes;
297*00c7fec1SAndroid Build Coastguard Worker                 rx_length -= rx_data_bytes;
298*00c7fec1SAndroid Build Coastguard Worker             }
299*00c7fec1SAndroid Build Coastguard Worker         }
300*00c7fec1SAndroid Build Coastguard Worker 
301*00c7fec1SAndroid Build Coastguard Worker         // If the response has a continuation flag we need to prompt for more data by sending
302*00c7fec1SAndroid Build Coastguard Worker         // an empty packet.
303*00c7fec1SAndroid Build Coastguard Worker         if (rx_packet_[kIndexFlags] & kFlagContinuation) {
304*00c7fec1SAndroid Build Coastguard Worker             // We got a valid response so reset our attempt counter.
305*00c7fec1SAndroid Build Coastguard Worker             attempts_left = attempts;
306*00c7fec1SAndroid Build Coastguard Worker             header->Set(rx_packet_[kIndexId], sequence_, kFlagNone);
307*00c7fec1SAndroid Build Coastguard Worker             tx_data = nullptr;
308*00c7fec1SAndroid Build Coastguard Worker             tx_length = 0;
309*00c7fec1SAndroid Build Coastguard Worker             continue;
310*00c7fec1SAndroid Build Coastguard Worker         }
311*00c7fec1SAndroid Build Coastguard Worker 
312*00c7fec1SAndroid Build Coastguard Worker         break;
313*00c7fec1SAndroid Build Coastguard Worker     }
314*00c7fec1SAndroid Build Coastguard Worker 
315*00c7fec1SAndroid Build Coastguard Worker     if (attempts_left <= 0) {
316*00c7fec1SAndroid Build Coastguard Worker         *error = "no response from target";
317*00c7fec1SAndroid Build Coastguard Worker         return -1;
318*00c7fec1SAndroid Build Coastguard Worker     }
319*00c7fec1SAndroid Build Coastguard Worker 
320*00c7fec1SAndroid Build Coastguard Worker     if (rx_packet_[kIndexId] == kIdError) {
321*00c7fec1SAndroid Build Coastguard Worker         *error = "target reported error: " + *error;
322*00c7fec1SAndroid Build Coastguard Worker         return -1;
323*00c7fec1SAndroid Build Coastguard Worker     }
324*00c7fec1SAndroid Build Coastguard Worker 
325*00c7fec1SAndroid Build Coastguard Worker     return total_data_bytes;
326*00c7fec1SAndroid Build Coastguard Worker }
327*00c7fec1SAndroid Build Coastguard Worker 
Read(void * data,size_t length)328*00c7fec1SAndroid Build Coastguard Worker ssize_t UdpTransport::Read(void* data, size_t length) {
329*00c7fec1SAndroid Build Coastguard Worker     // Read from the target by sending an empty packet.
330*00c7fec1SAndroid Build Coastguard Worker     std::string error;
331*00c7fec1SAndroid Build Coastguard Worker     ssize_t bytes = SendData(kIdFastboot, nullptr, 0, reinterpret_cast<uint8_t*>(data), length,
332*00c7fec1SAndroid Build Coastguard Worker                              kMaxTransmissionAttempts, &error);
333*00c7fec1SAndroid Build Coastguard Worker 
334*00c7fec1SAndroid Build Coastguard Worker     if (bytes == -1) {
335*00c7fec1SAndroid Build Coastguard Worker         fprintf(stderr, "UDP error: %s\n", error.c_str());
336*00c7fec1SAndroid Build Coastguard Worker         return -1;
337*00c7fec1SAndroid Build Coastguard Worker     } else if (static_cast<size_t>(bytes) > length) {
338*00c7fec1SAndroid Build Coastguard Worker         // Fastboot protocol error: the target sent more data than our fastboot engine was prepared
339*00c7fec1SAndroid Build Coastguard Worker         // to receive.
340*00c7fec1SAndroid Build Coastguard Worker         fprintf(stderr, "UDP error: receive overflow, target sent too much fastboot data\n");
341*00c7fec1SAndroid Build Coastguard Worker         return -1;
342*00c7fec1SAndroid Build Coastguard Worker     }
343*00c7fec1SAndroid Build Coastguard Worker 
344*00c7fec1SAndroid Build Coastguard Worker     return bytes;
345*00c7fec1SAndroid Build Coastguard Worker }
346*00c7fec1SAndroid Build Coastguard Worker 
Write(const void * data,size_t length)347*00c7fec1SAndroid Build Coastguard Worker ssize_t UdpTransport::Write(const void* data, size_t length) {
348*00c7fec1SAndroid Build Coastguard Worker     std::string error;
349*00c7fec1SAndroid Build Coastguard Worker     ssize_t bytes = SendData(kIdFastboot, reinterpret_cast<const uint8_t*>(data), length, nullptr,
350*00c7fec1SAndroid Build Coastguard Worker                              0, kMaxTransmissionAttempts, &error);
351*00c7fec1SAndroid Build Coastguard Worker 
352*00c7fec1SAndroid Build Coastguard Worker     if (bytes == -1) {
353*00c7fec1SAndroid Build Coastguard Worker         fprintf(stderr, "UDP error: %s\n", error.c_str());
354*00c7fec1SAndroid Build Coastguard Worker         return -1;
355*00c7fec1SAndroid Build Coastguard Worker     } else if (bytes > 0) {
356*00c7fec1SAndroid Build Coastguard Worker         // UDP protocol error: only empty ACK packets are allowed when writing to a device.
357*00c7fec1SAndroid Build Coastguard Worker         fprintf(stderr, "UDP error: target sent fastboot data out-of-turn\n");
358*00c7fec1SAndroid Build Coastguard Worker         return -1;
359*00c7fec1SAndroid Build Coastguard Worker     }
360*00c7fec1SAndroid Build Coastguard Worker 
361*00c7fec1SAndroid Build Coastguard Worker     return length;
362*00c7fec1SAndroid Build Coastguard Worker }
363*00c7fec1SAndroid Build Coastguard Worker 
Close()364*00c7fec1SAndroid Build Coastguard Worker int UdpTransport::Close() {
365*00c7fec1SAndroid Build Coastguard Worker     if (socket_ == nullptr) {
366*00c7fec1SAndroid Build Coastguard Worker         return 0;
367*00c7fec1SAndroid Build Coastguard Worker     }
368*00c7fec1SAndroid Build Coastguard Worker 
369*00c7fec1SAndroid Build Coastguard Worker     int result = socket_->Close();
370*00c7fec1SAndroid Build Coastguard Worker     socket_.reset();
371*00c7fec1SAndroid Build Coastguard Worker     return result;
372*00c7fec1SAndroid Build Coastguard Worker }
373*00c7fec1SAndroid Build Coastguard Worker 
Reset()374*00c7fec1SAndroid Build Coastguard Worker int UdpTransport::Reset() {
375*00c7fec1SAndroid Build Coastguard Worker     return 0;
376*00c7fec1SAndroid Build Coastguard Worker }
377*00c7fec1SAndroid Build Coastguard Worker 
Connect(const std::string & hostname,int port,std::string * error)378*00c7fec1SAndroid Build Coastguard Worker std::unique_ptr<Transport> Connect(const std::string& hostname, int port, std::string* error) {
379*00c7fec1SAndroid Build Coastguard Worker     return internal::Connect(Socket::NewClient(Socket::Protocol::kUdp, hostname, port, error),
380*00c7fec1SAndroid Build Coastguard Worker                              error);
381*00c7fec1SAndroid Build Coastguard Worker }
382*00c7fec1SAndroid Build Coastguard Worker 
383*00c7fec1SAndroid Build Coastguard Worker namespace internal {
384*00c7fec1SAndroid Build Coastguard Worker 
Connect(std::unique_ptr<Socket> sock,std::string * error)385*00c7fec1SAndroid Build Coastguard Worker std::unique_ptr<Transport> Connect(std::unique_ptr<Socket> sock, std::string* error) {
386*00c7fec1SAndroid Build Coastguard Worker     if (sock == nullptr) {
387*00c7fec1SAndroid Build Coastguard Worker         // If Socket creation failed |error| is already set.
388*00c7fec1SAndroid Build Coastguard Worker         return nullptr;
389*00c7fec1SAndroid Build Coastguard Worker     }
390*00c7fec1SAndroid Build Coastguard Worker 
391*00c7fec1SAndroid Build Coastguard Worker     return UdpTransport::NewTransport(std::move(sock), error);
392*00c7fec1SAndroid Build Coastguard Worker }
393*00c7fec1SAndroid Build Coastguard Worker 
394*00c7fec1SAndroid Build Coastguard Worker }  // namespace internal
395*00c7fec1SAndroid Build Coastguard Worker 
396*00c7fec1SAndroid Build Coastguard Worker }  // namespace udp
397