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

Commit 1e57ab6f authored by David Pursell's avatar David Pursell Committed by android-build-merger
Browse files

Merge "adb: support forwarding TCP port 0." am: cb90562b

am: 5aaffac3

* commit '5aaffac3':
  adb: support forwarding TCP port 0.

Change-Id: I2e7bd29de76a87b80e71ce00ed2da4666f3cbb56
parents 12397f20 5aaffac3
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -58,6 +58,7 @@ LIBADB_SRC_FILES := \

LIBADB_TEST_SRCS := \
    adb_io_test.cpp \
    adb_listeners_test.cpp \
    adb_utils_test.cpp \
    fdevent_test.cpp \
    socket_test.cpp \
+10 −3
Original line number Diff line number Diff line
@@ -955,18 +955,25 @@ int handle_forward_request(const char* service, TransportType type, const char*

        std::string error;
        InstallStatus r;
        int resolved_tcp_port = 0;
        if (kill_forward) {
            r = remove_listener(pieces[0].c_str(), transport);
        } else {
            r = install_listener(pieces[0], pieces[1].c_str(), transport,
                                 no_rebind, &error);
            r = install_listener(pieces[0], pieces[1].c_str(), transport, no_rebind,
                                 &resolved_tcp_port, &error);
        }
        if (r == INSTALL_STATUS_OK) {
#if ADB_HOST
            /* On the host: 1st OKAY is connect, 2nd OKAY is status */
            // On the host: 1st OKAY is connect, 2nd OKAY is status.
            SendOkay(reply_fd);
#endif
            SendOkay(reply_fd);

            // If a TCP port was resolved, send the actual port number back.
            if (resolved_tcp_port != 0) {
                SendProtocolString(reply_fd, android::base::StringPrintf("%d", resolved_tcp_port));
            }

            return 1;
        }

+1 −24
Original line number Diff line number Diff line
@@ -50,7 +50,7 @@ constexpr size_t MAX_PAYLOAD = MAX_PAYLOAD_V2;
std::string adb_version();

// Increment this when we want to force users to start a new adb server.
#define ADB_SERVER_VERSION 36
#define ADB_SERVER_VERSION 37

class atransport;
struct usb_handle;
@@ -116,29 +116,6 @@ enum ConnectionState {
    kCsUnauthorized,
};

/* A listener is an entity which binds to a local port
** and, upon receiving a connection on that port, creates
** an asocket to connect the new local connection to a
** specific remote service.
**
** TODO: some listeners read from the new connection to
** determine what exact service to connect to on the far
** side.
*/
struct alistener
{
    alistener *next;
    alistener *prev;

    fdevent fde;
    int fd;

    char *local_name;
    char *connect_to;
    atransport *transport;
    adisconnect  disconnect;
};


void print_packet(const char *label, apacket *p);

+111 −116
Original line number Diff line number Diff line
@@ -20,18 +20,55 @@
#include <stdlib.h>

#include <android-base/stringprintf.h>
#include <android-base/strings.h>
#include <cutils/sockets.h>

#include "sysdeps.h"
#include "transport.h"

int gListenAll = 0; /* Not static because it is used in commandline.c. */

static alistener listener_list = {
    .next = &listener_list,
    .prev = &listener_list,
// Not static because it is used in commandline.c.
int gListenAll = 0;

// A listener is an entity which binds to a local port and, upon receiving a connection on that
// port, creates an asocket to connect the new local connection to a specific remote service.
//
// TODO: some listeners read from the new connection to determine what exact service to connect to
// on the far side.
class alistener {
  public:
    alistener(const std::string& _local_name, const std::string& _connect_to);
    ~alistener();

    fdevent fde;
    int fd = -1;

    std::string local_name;
    std::string connect_to;
    atransport* transport = nullptr;
    adisconnect disconnect;

  private:
    DISALLOW_COPY_AND_ASSIGN(alistener);
};

alistener::alistener(const std::string& _local_name, const std::string& _connect_to)
    : local_name(_local_name), connect_to(_connect_to) {
}

alistener::~alistener() {
    // Closes the corresponding fd.
    fdevent_remove(&fde);

    if (transport) {
        transport->RemoveDisconnect(&disconnect);
    }
}

// listener_list retains ownership of all created alistener objects. Removing an alistener from
// this list will cause it to be deleted.
typedef std::list<std::unique_ptr<alistener>> ListenerList;
static ListenerList& listener_list = *new ListenerList();

static void ss_listener_event_func(int _fd, unsigned ev, void *_l) {
    if (ev & FDE_READ) {
        sockaddr_storage ss;
@@ -73,7 +110,7 @@ static void listener_event_func(int _fd, unsigned ev, void* _l)
        s = create_local_socket(fd);
        if (s) {
            s->transport = listener->transport;
            connect_to_remote(s, listener->connect_to);
            connect_to_remote(s, listener->connect_to.c_str());
            return;
        }

@@ -81,66 +118,63 @@ static void listener_event_func(int _fd, unsigned ev, void* _l)
    }
}

static void free_listener(alistener*  l)
{
    if (l->next) {
        l->next->prev = l->prev;
        l->prev->next = l->next;
        l->next = l->prev = l;
    }

    // closes the corresponding fd
    fdevent_remove(&l->fde);

    if (l->local_name)
        free((char*)l->local_name);

    if (l->connect_to)
        free((char*)l->connect_to);

    if (l->transport) {
        l->transport->RemoveDisconnect(&l->disconnect);
// Called as a transport disconnect function. |arg| is the raw alistener*.
static void listener_disconnect(void* arg, atransport*) {
    for (auto iter = listener_list.begin(); iter != listener_list.end(); ++iter) {
        if (iter->get() == arg) {
            (*iter)->transport = nullptr;
            listener_list.erase(iter);
            return;
        }
    free(l);
    }

static void listener_disconnect(void* arg, atransport*) {
    alistener* listener = reinterpret_cast<alistener*>(arg);
    listener->transport = nullptr;
    free_listener(listener);
}

static int local_name_to_fd(const char* name, std::string* error) {
    if (!strncmp("tcp:", name, 4)) {
        int port = atoi(name + 4);
int local_name_to_fd(alistener* listener, int* resolved_tcp_port, std::string* error) {
    if (android::base::StartsWith(listener->local_name, "tcp:")) {
        int requested_port = atoi(&listener->local_name[4]);
        int sock = -1;
        if (gListenAll > 0) {
            return network_inaddr_any_server(port, SOCK_STREAM, error);
            sock = network_inaddr_any_server(requested_port, SOCK_STREAM, error);
        } else {
            return network_loopback_server(port, SOCK_STREAM, error);
            sock = network_loopback_server(requested_port, SOCK_STREAM, error);
        }

        // If the caller requested port 0, update the listener name with the resolved port.
        if (sock >= 0 && requested_port == 0) {
            int local_port = adb_socket_get_local_port(sock);
            if (local_port > 0) {
                listener->local_name = android::base::StringPrintf("tcp:%d", local_port);
                if (resolved_tcp_port != nullptr) {
                    *resolved_tcp_port = local_port;
                }
            }
        }

        return sock;
    }
#if !defined(_WIN32)  // No Unix-domain sockets on Windows.
    // It's nonsensical to support the "reserved" space on the adb host side
    if (!strncmp(name, "local:", 6)) {
        return network_local_server(name + 6,
                ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM, error);
    } else if (!strncmp(name, "localabstract:", 14)) {
        return network_local_server(name + 14,
                ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM, error);
    } else if (!strncmp(name, "localfilesystem:", 16)) {
        return network_local_server(name + 16,
                ANDROID_SOCKET_NAMESPACE_FILESYSTEM, SOCK_STREAM, error);
    // It's nonsensical to support the "reserved" space on the adb host side.
    if (android::base::StartsWith(listener->local_name, "local:")) {
        return network_local_server(&listener->local_name[6], ANDROID_SOCKET_NAMESPACE_ABSTRACT,
                                    SOCK_STREAM, error);
    } else if (android::base::StartsWith(listener->local_name, "localabstract:")) {
        return network_local_server(&listener->local_name[14], ANDROID_SOCKET_NAMESPACE_ABSTRACT,
                                    SOCK_STREAM, error);
    } else if (android::base::StartsWith(listener->local_name, "localfilesystem:")) {
        return network_local_server(&listener->local_name[16], ANDROID_SOCKET_NAMESPACE_FILESYSTEM,
                                    SOCK_STREAM, error);
    }

#endif
    *error = android::base::StringPrintf("unknown local portname '%s'", name);
    *error = android::base::StringPrintf("unknown local portname '%s'",
                                         listener->local_name.c_str());
    return -1;
}

// Write the list of current listeners (network redirections) into a string.
std::string format_listeners() {
    std::string result;
    for (alistener* l = listener_list.next; l != &listener_list; l = l->next) {
    for (auto& l : listener_list) {
        // Ignore special listeners like those for *smartsocket*
        if (l->connect_to[0] == '*') {
            continue;
@@ -149,65 +183,51 @@ std::string format_listeners() {
        // Entries from "adb reverse" have no serial.
        android::base::StringAppendF(&result, "%s %s %s\n",
                                     l->transport->serial ? l->transport->serial : "(reverse)",
                                     l->local_name, l->connect_to);
                                     l->local_name.c_str(), l->connect_to.c_str());
    }
    return result;
}

InstallStatus remove_listener(const char* local_name, atransport* transport) {
    alistener *l;

    for (l = listener_list.next; l != &listener_list; l = l->next) {
        if (!strcmp(local_name, l->local_name)) {
            free_listener(l);
    for (auto iter = listener_list.begin(); iter != listener_list.end(); ++iter) {
        if (local_name == (*iter)->local_name) {
            listener_list.erase(iter);
            return INSTALL_STATUS_OK;
        }
    }
    return INSTALL_STATUS_LISTENER_NOT_FOUND;
}

void remove_all_listeners(void)
{
    alistener *l, *l_next;
    for (l = listener_list.next; l != &listener_list; l = l_next) {
        l_next = l->next;
void remove_all_listeners() {
    auto iter = listener_list.begin();
    while (iter != listener_list.end()) {
        // Never remove smart sockets.
        if (l->connect_to[0] == '*')
            continue;
        free_listener(l);
        if ((*iter)->connect_to[0] == '*') {
            ++iter;
        } else {
            iter = listener_list.erase(iter);
        }
    }
}

InstallStatus install_listener(const std::string& local_name,
                                  const char *connect_to,
                                  atransport* transport,
                                  int no_rebind,
                                  std::string* error)
{
    for (alistener* l = listener_list.next; l != &listener_list; l = l->next) {
InstallStatus install_listener(const std::string& local_name, const char* connect_to,
                               atransport* transport, int no_rebind, int* resolved_tcp_port,
                               std::string* error) {
    for (auto& l : listener_list) {
        if (local_name == l->local_name) {
            char* cto;

            /* can't repurpose a smartsocket */
            // Can't repurpose a smartsocket.
            if(l->connect_to[0] == '*') {
                *error = "cannot repurpose smartsocket";
                return INSTALL_STATUS_INTERNAL_ERROR;
            }

            /* can't repurpose a listener if 'no_rebind' is true */
            // Can't repurpose a listener if 'no_rebind' is true.
            if (no_rebind) {
                *error = "cannot rebind";
                return INSTALL_STATUS_CANNOT_REBIND;
            }

            cto = strdup(connect_to);
            if(cto == 0) {
                *error = "cannot duplicate string";
                return INSTALL_STATUS_INTERNAL_ERROR;
            }

            free((void*) l->connect_to);
            l->connect_to = cto;
            l->connect_to = connect_to;
            if (l->transport != transport) {
                l->transport->RemoveDisconnect(&l->disconnect);
                l->transport = transport;
@@ -217,54 +237,29 @@ InstallStatus install_listener(const std::string& local_name,
        }
    }

    alistener* listener = reinterpret_cast<alistener*>(
        calloc(1, sizeof(alistener)));
    if (listener == nullptr) {
        goto nomem;
    }

    listener->local_name = strdup(local_name.c_str());
    if (listener->local_name == nullptr) {
        goto nomem;
    }

    listener->connect_to = strdup(connect_to);
    if (listener->connect_to == nullptr) {
        goto nomem;
    }
    std::unique_ptr<alistener> listener(new alistener(local_name, connect_to));

    listener->fd = local_name_to_fd(listener->local_name, error);
    listener->fd = local_name_to_fd(listener.get(), resolved_tcp_port, error);
    if (listener->fd < 0) {
        free(listener->local_name);
        free(listener->connect_to);
        free(listener);
        return INSTALL_STATUS_CANNOT_BIND;
    }

    close_on_exec(listener->fd);
    if (!strcmp(listener->connect_to, "*smartsocket*")) {
        fdevent_install(&listener->fde, listener->fd, ss_listener_event_func,
                        listener);
    if (listener->connect_to == "*smartsocket*") {
        fdevent_install(&listener->fde, listener->fd, ss_listener_event_func, listener.get());
    } else {
        fdevent_install(&listener->fde, listener->fd, listener_event_func,
                        listener);
        fdevent_install(&listener->fde, listener->fd, listener_event_func, listener.get());
    }
    fdevent_set(&listener->fde, FDE_READ);

    listener->next = &listener_list;
    listener->prev = listener_list.prev;
    listener->next->prev = listener;
    listener->prev->next = listener;
    listener->transport = transport;

    if (transport) {
        listener->disconnect.opaque = listener;
        listener->disconnect.opaque = listener.get();
        listener->disconnect.func   = listener_disconnect;
        transport->AddDisconnect(&listener->disconnect);
    }
    return INSTALL_STATUS_OK;

nomem:
    fatal("cannot allocate listener");
    return INSTALL_STATUS_INTERNAL_ERROR;
    listener_list.push_back(std::move(listener));
    return INSTALL_STATUS_OK;
}
+4 −4
Original line number Diff line number Diff line
@@ -21,6 +21,8 @@

#include <string>

#include <android-base/macros.h>

// error/status codes for install_listener.
enum InstallStatus {
  INSTALL_STATUS_OK = 0,
@@ -30,10 +32,8 @@ enum InstallStatus {
  INSTALL_STATUS_LISTENER_NOT_FOUND = -4,
};

InstallStatus install_listener(const std::string& local_name,
                               const char* connect_to,
                               atransport* transport,
                               int no_rebind,
InstallStatus install_listener(const std::string& local_name, const char* connect_to,
                               atransport* transport, int no_rebind, int* resolved_tcp_port,
                               std::string* error);

std::string format_listeners();
Loading