diff options
-rw-r--r-- | adb/SERVICES.TXT | 17 | ||||
-rw-r--r-- | adb/adb.c | 221 | ||||
-rw-r--r-- | adb/adb.h | 2 | ||||
-rw-r--r-- | adb/commandline.c | 38 | ||||
-rw-r--r-- | adb/services.c | 21 |
5 files changed, 198 insertions, 101 deletions
diff --git a/adb/SERVICES.TXT b/adb/SERVICES.TXT index 7f85dc3..63000f2 100644 --- a/adb/SERVICES.TXT +++ b/adb/SERVICES.TXT @@ -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'. @@ -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; @@ -1427,6 +1438,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; @@ -1547,97 +1672,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); @@ -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, diff --git a/adb/commandline.c b/adb/commandline.c index a3eaf43..70bf641 100644 --- a/adb/commandline.c +++ b/adb/commandline.c @@ -137,6 +137,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] [-d] [-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" @@ -1308,8 +1321,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; @@ -1338,15 +1354,19 @@ top: } // Determine the <host-prefix> for this command. - if (serial) { - snprintf(host_prefix, sizeof host_prefix, "host-serial:%s", - serial); - } else if (ttype == kTransportUsb) { - snprintf(host_prefix, sizeof host_prefix, "host-usb"); - } else if (ttype == kTransportLocal) { - snprintf(host_prefix, sizeof host_prefix, "host-local"); + if (reverse) { + snprintf(host_prefix, sizeof host_prefix, "reverse"); } else { - snprintf(host_prefix, sizeof host_prefix, "host"); + if (serial) { + snprintf(host_prefix, sizeof host_prefix, "host-serial:%s", + serial); + } else if (ttype == kTransportUsb) { + snprintf(host_prefix, sizeof host_prefix, "host-usb"); + } else if (ttype == kTransportLocal) { + snprintf(host_prefix, sizeof host_prefix, "host-local"); + } else { + snprintf(host_prefix, sizeof host_prefix, "host"); + } } // Implement forward --list diff --git a/adb/services.c b/adb/services.c index e25a232..7b809da 100644 --- a/adb/services.c +++ b/adb/services.c @@ -141,6 +141,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) @@ -385,6 +396,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) { |