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

Commit 6e7343b8 authored by David 'Digit' Turner's avatar David 'Digit' Turner Committed by Gerrit Code Review
Browse files

Merge "adb: implement "adb reverse <local> <remote>""

parents 5fe6fcc3 25258694
Loading
Loading
Loading
Loading
+17 −0
Original line number Diff line number Diff line
@@ -240,3 +240,20 @@ sync:
    This starts the file synchronisation service, used to implement "adb push"
    and "adb pull". Since this service is pretty complex, it will be detailed
    in a companion document named SYNC.TXT

reverse:<forward-command>
    This implements the 'adb reverse' feature, i.e. the ability to reverse
    socket connections from a device to the host. <forward-command> is one
    of the forwarding commands that are described above, as in:

      list-forward
      forward:<local>;<remote>
      forward:norebind:<local>;<remote>
      killforward-all
      killforward:<local>

    Note that in this case, <local> corresponds to the socket on the device
    and <remote> corresponds to the socket on the host.

    The output of reverse:list-forward is the same as host:list-forward
    except that <serial> will be just 'host'.
+129 −92
Original line number Diff line number Diff line
@@ -318,7 +318,18 @@ static size_t fill_connect_data(char *buf, size_t bufsize)
#endif
}

static void send_msg_with_okay(int fd, char* msg, size_t msglen) {
#if !ADB_HOST
static void send_msg_with_header(int fd, const char* msg, size_t msglen) {
    char header[5];
    if (msglen > 0xffff)
        msglen = 0xffff;
    snprintf(header, sizeof(header), "%04x", (unsigned)msglen);
    writex(fd, header, 4);
    writex(fd, msg, msglen);
}
#endif

static void send_msg_with_okay(int fd, const char* msg, size_t msglen) {
    char header[9];
    if (msglen > 0xffff)
        msglen = 0xffff;
@@ -1428,6 +1439,120 @@ int adb_main(int is_daemon, int server_port)
    return 0;
}

// Try to handle a network forwarding request.
// This returns 1 on success, 0 on failure, and -1 to indicate this is not
// a forwarding-related request.
int handle_forward_request(const char* service, transport_type ttype, char* serial, int reply_fd)
{
    if (!strcmp(service, "list-forward")) {
        // Create the list of forward redirections.
        int buffer_size = format_listeners(NULL, 0);
        // Add one byte for the trailing zero.
        char* buffer = malloc(buffer_size + 1);
        if (buffer == NULL) {
            sendfailmsg(reply_fd, "not enough memory");
            return 1;
        }
        (void) format_listeners(buffer, buffer_size + 1);
#if ADB_HOST
        send_msg_with_okay(reply_fd, buffer, buffer_size);
#else
        send_msg_with_header(reply_fd, buffer, buffer_size);
#endif
        free(buffer);
        return 1;
    }

    if (!strcmp(service, "killforward-all")) {
        remove_all_listeners();
#if ADB_HOST
        /* On the host: 1st OKAY is connect, 2nd OKAY is status */
        adb_write(reply_fd, "OKAY", 4);
#endif
        adb_write(reply_fd, "OKAY", 4);
        return 1;
    }

    if (!strncmp(service, "forward:",8) ||
        !strncmp(service, "killforward:",12)) {
        char *local, *remote, *err;
        int r;
        atransport *transport;

        int createForward = strncmp(service, "kill", 4);
        int no_rebind = 0;

        local = strchr(service, ':') + 1;

        // Handle forward:norebind:<local>... here
        if (createForward && !strncmp(local, "norebind:", 9)) {
            no_rebind = 1;
            local = strchr(local, ':') + 1;
        }

        remote = strchr(local,';');

        if (createForward) {
            // Check forward: parameter format: '<local>;<remote>'
            if(remote == 0) {
                sendfailmsg(reply_fd, "malformed forward spec");
                return 1;
            }

            *remote++ = 0;
            if((local[0] == 0) || (remote[0] == 0) || (remote[0] == '*')) {
                sendfailmsg(reply_fd, "malformed forward spec");
                return 1;
            }
        } else {
            // Check killforward: parameter format: '<local>'
            if (local[0] == 0) {
                sendfailmsg(reply_fd, "malformed forward spec");
                return 1;
            }
        }

        transport = acquire_one_transport(CS_ANY, ttype, serial, &err);
        if (!transport) {
            sendfailmsg(reply_fd, err);
            return 1;
        }

        if (createForward) {
            r = install_listener(local, remote, transport, no_rebind);
        } else {
            r = remove_listener(local, transport);
        }
        if(r == 0) {
#if ADB_HOST
            /* On the host: 1st OKAY is connect, 2nd OKAY is status */
            writex(reply_fd, "OKAY", 4);
#endif
            writex(reply_fd, "OKAY", 4);
            return 1;
        }

        if (createForward) {
            const char* message;
            switch (r) {
              case INSTALL_STATUS_CANNOT_BIND:
                message = "cannot bind to socket";
                break;
              case INSTALL_STATUS_CANNOT_REBIND:
                message = "cannot rebind existing socket";
                break;
              default:
                message = "internal error";
            }
            sendfailmsg(reply_fd, message);
        } else {
            sendfailmsg(reply_fd, "cannot remove listener");
        }
        return 1;
    }
    return 0;
}

int handle_host_request(char *service, transport_type ttype, char* serial, int reply_fd, asocket *s)
{
    atransport *transport = NULL;
@@ -1548,97 +1673,9 @@ int handle_host_request(char *service, transport_type ttype, char* serial, int r
    }
#endif // ADB_HOST

    if(!strcmp(service,"list-forward")) {
        // Create the list of forward redirections.
        int buffer_size = format_listeners(NULL, 0);
        // Add one byte for the trailing zero.
        char* buffer = malloc(buffer_size+1);
        (void) format_listeners(buffer, buffer_size+1);
        send_msg_with_okay(reply_fd, buffer, buffer_size);
        free(buffer);
        return 0;
    }

    if (!strcmp(service,"killforward-all")) {
        remove_all_listeners();
        adb_write(reply_fd, "OKAYOKAY", 8);
        return 0;
    }

    if(!strncmp(service,"forward:",8) ||
       !strncmp(service,"killforward:",12)) {
        char *local, *remote, *err;
        int r;
        atransport *transport;

        int createForward = strncmp(service,"kill",4);
        int no_rebind = 0;

        local = strchr(service, ':') + 1;

        // Handle forward:norebind:<local>... here
        if (createForward && !strncmp(local, "norebind:", 9)) {
            no_rebind = 1;
            local = strchr(local, ':') + 1;
        }

        remote = strchr(local,';');

        if (createForward) {
            // Check forward: parameter format: '<local>;<remote>'
            if(remote == 0) {
                sendfailmsg(reply_fd, "malformed forward spec");
                return 0;
            }

            *remote++ = 0;
            if((local[0] == 0) || (remote[0] == 0) || (remote[0] == '*')){
                sendfailmsg(reply_fd, "malformed forward spec");
                return 0;
            }
        } else {
            // Check killforward: parameter format: '<local>'
            if (local[0] == 0) {
                sendfailmsg(reply_fd, "malformed forward spec");
                return 0;
            }
        }

        transport = acquire_one_transport(CS_ANY, ttype, serial, &err);
        if (!transport) {
            sendfailmsg(reply_fd, err);
            return 0;
        }

        if (createForward) {
            r = install_listener(local, remote, transport, no_rebind);
        } else {
            r = remove_listener(local, transport);
        }
        if(r == 0) {
                /* 1st OKAY is connect, 2nd OKAY is status */
            writex(reply_fd, "OKAYOKAY", 8);
            return 0;
        }

        if (createForward) {
            const char* message;
            switch (r) {
              case INSTALL_STATUS_CANNOT_BIND:
                message = "cannot bind to socket";
                break;
              case INSTALL_STATUS_CANNOT_REBIND:
                message = "cannot rebind existing socket";
                break;
              default:
                message = "internal error";
            }
            sendfailmsg(reply_fd, message);
        } else {
            sendfailmsg(reply_fd, "cannot remove listener");
        }
        return 0;
    }
    int ret = handle_forward_request(service, ttype, serial, reply_fd);
    if (ret >= 0)
      return ret - 1;

    if(!strncmp(service,"get-state",strlen("get-state"))) {
        transport = acquire_one_transport(CS_ANY, ttype, serial, NULL);
+2 −0
Original line number Diff line number Diff line
@@ -323,6 +323,8 @@ asocket* create_jdwp_tracker_service_socket();
int       create_jdwp_connection_fd(int  jdwp_pid);
#endif

int handle_forward_request(const char* service, transport_type ttype, char* serial, int reply_fd);

#if !ADB_HOST
typedef enum {
    BACKUP,
+29 −9
Original line number Diff line number Diff line
@@ -136,6 +136,19 @@ void help()
        "                                 if <local> is already forwarded\n"
        "  adb forward --remove <local> - remove a specific forward socket connection\n"
        "  adb forward --remove-all     - remove all forward socket connections\n"
        "  adb reverse --list           - list all reverse socket connections from device\n"
        "  adb reverse <remote> <local> - reverse socket connections\n"
        "                                 reverse specs are one of:\n"
        "                                   tcp:<port>\n"
        "                                   localabstract:<unix domain socket name>\n"
        "                                   localreserved:<unix domain socket name>\n"
        "                                   localfilesystem:<unix domain socket name>\n"
        "  adb reverse --norebind <remote> <local>\n"
        "                               - same as 'adb reverse <remote> <local>' but fails\n"
        "                                 if <remote> is already reversed.\n"
        "  adb reverse --remove <remote>\n"
        "                               - remove a specific reversed socket connection\n"
        "  adb reverse --remove-all     - remove all reversed socket connections from device\n"
        "  adb jdwp                     - list PIDs of processes hosting a JDWP transport\n"
        "  adb install [-l] [-r] [-s] [--algo <algorithm name> --key <hex-encoded key> --iv <hex-encoded iv>] <file>\n"
        "                               - push this package file to the device and install it\n"
@@ -1299,8 +1312,11 @@ top:
        return 0;
    }

    if(!strcmp(argv[0], "forward")) {
    if(!strcmp(argv[0], "forward") ||
       !strcmp(argv[0], "reverse"))
    {
        char host_prefix[64];
        char reverse = (char) !strcmp(argv[0], "reverse");
        char remove = 0;
        char remove_all = 0;
        char list = 0;
@@ -1329,6 +1345,9 @@ top:
        }

        // Determine the <host-prefix> for this command.
        if (reverse) {
            snprintf(host_prefix, sizeof host_prefix, "reverse");
        } else {
            if (serial) {
                snprintf(host_prefix, sizeof host_prefix, "host-serial:%s",
                        serial);
@@ -1339,6 +1358,7 @@ top:
            } else {
                snprintf(host_prefix, sizeof host_prefix, "host");
            }
        }

        // Implement forward --list
        if (list) {
+21 −0
Original line number Diff line number Diff line
@@ -154,6 +154,17 @@ cleanup:
    adb_close(fd);
}

void reverse_service(int fd, void* arg)
{
    const char* command = arg;

    if (handle_forward_request(command, kTransportAny, NULL, fd) < 0) {
        sendfailmsg(fd, "not a reverse forwarding command");
    }
    free(arg);
    adb_close(fd);
}

#endif

static int create_service_thread(void (*func)(int, void *), void *cookie)
@@ -398,6 +409,16 @@ int service_to_fd(const char *name)
        ret = create_service_thread(restart_tcp_service, (void *) (uintptr_t) port);
    } else if(!strncmp(name, "usb:", 4)) {
        ret = create_service_thread(restart_usb_service, NULL);
    } else if (!strncmp(name, "reverse:", 8)) {
        char* cookie = strdup(name + 8);
        if (cookie == NULL) {
            ret = -1;
        } else {
            ret = create_service_thread(reverse_service, cookie);
            if (ret < 0) {
                free(cookie);
            }
        }
#endif
    }
    if (ret >= 0) {