Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4785554c authored by Dmitrii Merkurev's avatar Dmitrii Merkurev
Browse files

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: default avatarDmitrii Merkurev <dimorinny@google.com>
parent 45380e4a
Loading
Loading
Loading
Loading
+46 −22
Original line number Diff line number Diff line
@@ -342,30 +342,49 @@ struct NetworkSerial {
    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"
        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 @@ static Result<NetworkSerial> ParseNetworkSerial(const std::string& serial) {
// 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 @@ static Transport* open_device(const char* local_serial, bool wait_for_device = t
            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 @@ static Transport* open_device(const char* local_serial, bool wait_for_device = t
            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 @@ static Transport* open_device() {
            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 @@ static int Connect(int argc, char* argv[]) {
    }

    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 Connect(int argc, char* argv[]) {
}

static int Disconnect(const char* local_serial) {
    EXPECT(ParseNetworkSerial(local_serial));
    Expect(ParseNetworkSerial(local_serial));

    ConnectedDevicesStorage storage;
    {
@@ -1555,7 +1579,7 @@ void reboot_to_userspace_fastboot() {
    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());

+10 −2
Original line number Diff line number Diff line
@@ -18,8 +18,16 @@ using android::base::Error;
using android::base::Result;
using android::base::ResultError;

#define EXPECT(result) \
    (result.ok() ? result.value() : (LOG(FATAL) << result.error().message(), result.value()))
template <typename T, typename U>
inline T Expect(Result<T, U> r) {
    if (r.ok()) {
        return r.value();
    }

    LOG(FATAL) << r.error().message();

    return r.value();
}

using SparsePtr = std::unique_ptr<sparse_file, decltype(&sparse_file_destroy)>;