fastboot: Fix IPv6 connect and -s host parsing
During fastboot connect / disconnect introduction, we
completely broke the IPv6 support (it was considering
all IPv6 addresses as a USB serial).
Makeing sure this problem isn't reproducible anymore
alongside with fixing EXCPECT causing process crash
and improve network serial error detection.
Bug: 271152365
Change-Id: Ic52aa5fff1948a64ac3d2672f3cf4d2b022e5cea
Signed-off-by: Dmitrii Merkurev <dimorinny@google.com>
diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp
index 799c9f9..602ba01 100644
--- a/fastboot/fastboot.cpp
+++ b/fastboot/fastboot.cpp
@@ -342,30 +342,49 @@
int port;
};
-static Result<NetworkSerial> ParseNetworkSerial(const std::string& serial) {
- const auto serial_parsed = android::base::Tokenize(serial, ":");
- const auto parsed_segments_count = serial_parsed.size();
- if (parsed_segments_count != 2 && parsed_segments_count != 3) {
- return Error() << "invalid network address: " << serial << ". Expected format:\n"
- << "<protocol>:<address>:<port> (tcp:localhost:5554)";
- }
+class ParseNetworkAddressError {
+ public:
+ enum Type { WRONG_PREFIX = 1, WRONG_ADDRESS = 2 };
+ ParseNetworkAddressError(Type&& type) : type_(std::forward<Type>(type)) {}
+
+ Type value() const { return type_; }
+ operator Type() const { return value(); }
+ std::string print() const { return ""; }
+
+ private:
+ Type type_;
+};
+
+static Result<NetworkSerial, ParseNetworkAddressError> ParseNetworkSerial(
+ const std::string& serial) {
Socket::Protocol protocol;
- if (serial_parsed[0] == "tcp") {
+ const char* net_address = nullptr;
+ int port = 0;
+
+ if (android::base::StartsWith(serial, "tcp:")) {
protocol = Socket::Protocol::kTcp;
- } else if (serial_parsed[0] == "udp") {
+ net_address = serial.c_str() + strlen("tcp:");
+ port = tcp::kDefaultPort;
+ } else if (android::base::StartsWith(serial, "udp:")) {
protocol = Socket::Protocol::kUdp;
+ net_address = serial.c_str() + strlen("udp:");
+ port = udp::kDefaultPort;
} else {
- return Error() << "invalid network address: " << serial << ". Expected format:\n"
- << "<protocol>:<address>:<port> (tcp:localhost:5554)";
+ return Error<ParseNetworkAddressError>(ParseNetworkAddressError::Type::WRONG_PREFIX)
+ << "protocol prefix ('tcp:' or 'udp:') is missed: " << serial << ". "
+ << "Expected address format:\n"
+ << "<protocol>:<address>:<port> (tcp:localhost:5554)";
}
- int port = 5554;
- if (parsed_segments_count == 3) {
- android::base::ParseInt(serial_parsed[2], &port, 5554);
+ std::string error;
+ std::string host;
+ if (!android::base::ParseNetAddress(net_address, &host, &port, nullptr, &error)) {
+ return Error<ParseNetworkAddressError>(ParseNetworkAddressError::Type::WRONG_ADDRESS)
+ << "invalid network address '" << net_address << "': " << error;
}
- return NetworkSerial{protocol, serial_parsed[1], port};
+ return NetworkSerial{protocol, host, port};
}
// Opens a new Transport connected to the particular device.
@@ -380,7 +399,8 @@
// object, and the caller should not attempt to delete the returned Transport.
static Transport* open_device(const char* local_serial, bool wait_for_device = true,
bool announce = true) {
- const Result<NetworkSerial> network_serial = ParseNetworkSerial(local_serial);
+ const Result<NetworkSerial, ParseNetworkAddressError> network_serial =
+ ParseNetworkSerial(local_serial);
Transport* transport = nullptr;
while (true) {
@@ -397,8 +417,12 @@
if (transport == nullptr && announce) {
LOG(ERROR) << "error: " << error;
}
- } else {
+ } else if (network_serial.error().code() == ParseNetworkAddressError::Type::WRONG_PREFIX) {
+ // WRONG_PREFIX is special because it happens when user wants to communicate with USB
+ // device
transport = usb_open(match_fastboot(local_serial));
+ } else {
+ Expect(network_serial);
}
if (transport != nullptr) {
@@ -413,7 +437,7 @@
announce = false;
LOG(ERROR) << "< waiting for " << local_serial << ">";
}
- std::this_thread::sleep_for(std::chrono::milliseconds(1));
+ std::this_thread::sleep_for(std::chrono::seconds(1));
}
}
@@ -476,7 +500,7 @@
announce = false;
LOG(ERROR) << "< waiting for any device >";
}
- std::this_thread::sleep_for(std::chrono::milliseconds(1));
+ std::this_thread::sleep_for(std::chrono::seconds(1));
}
}
@@ -487,7 +511,7 @@
}
const char* local_serial = *argv;
- EXPECT(ParseNetworkSerial(local_serial));
+ Expect(ParseNetworkSerial(local_serial));
const Transport* transport = open_device(local_serial, false);
if (transport == nullptr) {
@@ -506,7 +530,7 @@
}
static int Disconnect(const char* local_serial) {
- EXPECT(ParseNetworkSerial(local_serial));
+ Expect(ParseNetworkSerial(local_serial));
ConnectedDevicesStorage storage;
{
@@ -1555,7 +1579,7 @@
delete old_transport;
// Give the current connection time to close.
- std::this_thread::sleep_for(std::chrono::milliseconds(1000));
+ std::this_thread::sleep_for(std::chrono::seconds(1));
fb->set_transport(open_device());