diff options
author | David 'Digit' Turner <digit@android.com> | 2012-12-13 18:25:53 -0800 |
---|---|---|
committer | Android Git Automerger <android-git-automerger@android.com> | 2012-12-13 18:25:53 -0800 |
commit | 9bc6f20c618c45183af579e118dcf27b145b4e8c (patch) | |
tree | 14ab40374f124582751458906e2d8c23281e9859 /adb | |
parent | 625a8ef433d371704f024ca6391c87677c433169 (diff) | |
parent | abf7cc977e41540c45836d2fafd81606117f0399 (diff) | |
download | system_core-9bc6f20c618c45183af579e118dcf27b145b4e8c.zip system_core-9bc6f20c618c45183af579e118dcf27b145b4e8c.tar.gz system_core-9bc6f20c618c45183af579e118dcf27b145b4e8c.tar.bz2 |
am abf7cc97: am 13306d95: Merge "adb: Improve ADB\'s forward redirection management."
* commit 'abf7cc977e41540c45836d2fafd81606117f0399':
adb: Improve ADB's forward redirection management.
Diffstat (limited to 'adb')
-rw-r--r-- | adb/SERVICES.TXT | 27 | ||||
-rw-r--r-- | adb/adb.c | 177 | ||||
-rw-r--r-- | adb/commandline.c | 87 |
3 files changed, 258 insertions, 33 deletions
diff --git a/adb/SERVICES.TXT b/adb/SERVICES.TXT index d9aa09c..b53bc44 100644 --- a/adb/SERVICES.TXT +++ b/adb/SERVICES.TXT @@ -117,7 +117,34 @@ host:<request> or even any one of the local services described below. +<host-prefix>:forward:norebind:<local>;<remote> + Same as <host-prefix>:forward:<local>;<remote> except that it will + fail it there is already a forward connection from <local>. + Used to implement 'adb forward --no-rebind <local> <remote>' + +<host-prefix>:killforward:<local> + Remove any existing forward local connection from <local>. + This is used to implement 'adb forward --remove <local>' + +<host-prefix>:killforward-all + Remove all forward network connections. + This is used to implement 'adb forward --remove-all'. + +<host-prefix>:list-forward + List all existing forward connections from this server. + This returns something that looks like the following: + + <hex4>: The length of the payload, as 4 hexadecimal chars. + <payload>: A series of lines of the following format: + + <serial> " " <local> " " <remote> "\n" + + Where <serial> is a device serial number. + <local> is the host-specific endpoint (e.g. tcp:9000). + <remote> is the device-specific endpoint. + + Used to implement 'adb forward --list'. LOCAL SERVICES: @@ -722,24 +722,90 @@ int local_name_to_fd(const char *name) return -1; } -static int remove_listener(const char *local_name, const char *connect_to, atransport* transport) +// Write a single line describing a listener to a user-provided buffer. +// Appends a trailing zero, even in case of truncation, but the function +// returns the full line length. +// If |buffer| is NULL, does not write but returns required size. +static int format_listener(alistener* l, char* buffer, size_t buffer_len) { + // Format is simply: + // + // <device-serial> " " <local-name> " " <remote-name> "\n" + // + int local_len = strlen(l->local_name); + int connect_len = strlen(l->connect_to); + int serial_len = strlen(l->transport->serial); + + if (buffer != NULL) { + snprintf(buffer, buffer_len, "%s %s %s\n", + l->transport->serial, l->local_name, l->connect_to); + } + // NOTE: snprintf() on Windows returns -1 in case of truncation, so + // return the computed line length instead. + return local_len + connect_len + serial_len + 3; +} + +// Write the list of current listeners (network redirections) into a +// user-provided buffer. Appends a trailing zero, even in case of +// trunctaion, but return the full size in bytes. +// If |buffer| is NULL, does not write but returns required size. +static int format_listeners(char* buf, size_t buflen) +{ + alistener* l; + int result = 0; + for (l = listener_list.next; l != &listener_list; l = l->next) { + // Ignore special listeners like those for *smartsocket* + if (l->connect_to[0] == '*') + continue; + int len = format_listener(l, buf, buflen); + // Ensure there is space for the trailing zero. + result += len; + if (buf != NULL) { + buf += len; + buflen -= len; + if (buflen <= 0) + break; + } + } + return result; +} + +static int 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) && - !strcmp(connect_to, l->connect_to) && - l->transport && l->transport == transport) { - - listener_disconnect(l, transport); + if (!strcmp(local_name, l->local_name)) { + listener_disconnect(l, l->transport); return 0; } } - return -1; } -static int install_listener(const char *local_name, const char *connect_to, atransport* transport) +static void remove_all_listeners(void) +{ + alistener *l, *l_next; + for (l = listener_list.next; l != &listener_list; l = l_next) { + l_next = l->next; + // Never remove smart sockets. + if (l->connect_to[0] == '*') + continue; + listener_disconnect(l, l->transport); + } +} + +// error/status codes for install_listener. +typedef enum { + INSTALL_STATUS_OK = 0, + INSTALL_STATUS_INTERNAL_ERROR = -1, + INSTALL_STATUS_CANNOT_BIND = -2, + INSTALL_STATUS_CANNOT_REBIND = -3, +} install_status_t; + +static install_status_t install_listener(const char *local_name, + const char *connect_to, + atransport* transport, + int no_rebind) { alistener *l; @@ -751,12 +817,17 @@ static int install_listener(const char *local_name, const char *connect_to, atra /* can't repurpose a smartsocket */ if(l->connect_to[0] == '*') { - return -1; + return INSTALL_STATUS_INTERNAL_ERROR; + } + + /* can't repurpose a listener if 'no_rebind' is true */ + if (no_rebind) { + return INSTALL_STATUS_CANNOT_REBIND; } cto = strdup(connect_to); if(cto == 0) { - return -1; + return INSTALL_STATUS_INTERNAL_ERROR; } //printf("rebinding '%s' to '%s'\n", local_name, connect_to); @@ -767,7 +838,7 @@ static int install_listener(const char *local_name, const char *connect_to, atra l->transport = transport; add_transport_disconnect(l->transport, &l->disconnect); } - return 0; + return INSTALL_STATUS_OK; } } @@ -804,11 +875,11 @@ static int install_listener(const char *local_name, const char *connect_to, atra l->disconnect.func = listener_disconnect; add_transport_disconnect(transport, &l->disconnect); } - return 0; + return INSTALL_STATUS_OK; nomem: fatal("cannot allocate listener"); - return 0; + return INSTALL_STATUS_INTERNAL_ERROR; } #ifdef HAVE_WIN32_PROC @@ -1113,7 +1184,7 @@ int adb_main(int is_daemon, int server_port) char local_name[30]; build_local_name(local_name, sizeof(local_name), server_port); - if(install_listener(local_name, "*smartsocket*", NULL)) { + if(install_listener(local_name, "*smartsocket*", NULL, 0)) { exit(1); } #else @@ -1180,7 +1251,7 @@ int adb_main(int is_daemon, int server_port) } else { char local_name[30]; build_local_name(local_name, sizeof(local_name), server_port); - if(install_listener(local_name, "*smartsocket*", NULL)) { + if(install_listener(local_name, "*smartsocket*", NULL, 0)) { exit(1); } } @@ -1474,24 +1545,63 @@ int handle_host_request(char *service, transport_type ttype, char* serial, int r } #endif // ADB_HOST - if(!strncmp(service,"forward:",8) || !strncmp(service,"killforward:",12)) { + if(!strcmp(service,"list-forward")) { + // Create the list of forward redirections. + char header[9]; + 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); + snprintf(header, sizeof header, "OKAY%04x", buffer_size); + writex(reply_fd, header, 8); + writex(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 = service + (createForward ? 8 : 12); - remote = strchr(local,';'); - if(remote == 0) { - sendfailmsg(reply_fd, "malformed forward spec"); - return 0; + local = strchr(service, ':') + 1; + + // Handle forward:norebind:<local>... here + if (createForward && !strncmp(local, "norebind:", 9)) { + no_rebind = 1; + local = strchr(local, ':') + 1; } - *remote++ = 0; - if((local[0] == 0) || (remote[0] == 0) || (remote[0] == '*')){ - sendfailmsg(reply_fd, "malformed forward spec"); - return 0; + 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); @@ -1501,9 +1611,9 @@ int handle_host_request(char *service, transport_type ttype, char* serial, int r } if (createForward) { - r = install_listener(local, remote, transport); + r = install_listener(local, remote, transport, no_rebind); } else { - r = remove_listener(local, remote, transport); + r = remove_listener(local, transport); } if(r == 0) { /* 1st OKAY is connect, 2nd OKAY is status */ @@ -1512,7 +1622,18 @@ int handle_host_request(char *service, transport_type ttype, char* serial, int r } if (createForward) { - sendfailmsg(reply_fd, (r == -1) ? "cannot rebind smartsocket" : "cannot bind socket"); + 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"); } diff --git a/adb/commandline.c b/adb/commandline.c index 24cbb5a..a4c2f40 100644 --- a/adb/commandline.c +++ b/adb/commandline.c @@ -112,6 +112,9 @@ void help() " adb shell <command> - run remote shell command\n" " adb emu <command> - run emulator console command\n" " adb logcat [ <filter-spec> ] - View device log\n" + " adb forward --list - list all forward socket connections.\n" + " the format is a list of lines with the following format:\n" + " <serial> \" \" <local> \" \" <remote> \"\\n\"\n" " adb forward <local> <remote> - forward socket connections\n" " forward specs are one of: \n" " tcp:<port>\n" @@ -120,6 +123,11 @@ void help() " localfilesystem:<unix domain socket name>\n" " dev:<character device name>\n" " jdwp:<process pid> (remote only)\n" + " adb forward --no-rebind <local> <remote>\n" + " - same as 'adb forward <local> <remote>' but fails\n" + " 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 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" @@ -1223,16 +1231,85 @@ top: } if(!strcmp(argv[0], "forward")) { - if(argc != 3) return usage(); + char host_prefix[64]; + char remove = 0; + char remove_all = 0; + char list = 0; + char no_rebind = 0; + + // Parse options here. + while (argc > 1 && argv[1][0] == '-') { + if (!strcmp(argv[1], "--list")) + list = 1; + else if (!strcmp(argv[1], "--remove")) + remove = 1; + else if (!strcmp(argv[1], "--remove-all")) + remove_all = 1; + else if (!strcmp(argv[1], "--no-rebind")) + no_rebind = 1; + else { + return usage(); + } + argc--; + argv++; + } + + // Ensure we can only use one option at a time. + if (list + remove + remove_all + no_rebind > 1) { + return usage(); + } + + // Determine the <host-prefix> for this command. if (serial) { - snprintf(buf, sizeof buf, "host-serial:%s:forward:%s;%s",serial, argv[1], argv[2]); + snprintf(host_prefix, sizeof host_prefix, "host-serial:%s", + serial); } else if (ttype == kTransportUsb) { - snprintf(buf, sizeof buf, "host-usb:forward:%s;%s", argv[1], argv[2]); + snprintf(host_prefix, sizeof host_prefix, "host-usb"); } else if (ttype == kTransportLocal) { - snprintf(buf, sizeof buf, "host-local:forward:%s;%s", argv[1], argv[2]); + snprintf(host_prefix, sizeof host_prefix, "host-local"); } else { - snprintf(buf, sizeof buf, "host:forward:%s;%s", argv[1], argv[2]); + snprintf(host_prefix, sizeof host_prefix, "host"); } + + // Implement forward --list + if (list) { + if (argc != 1) + return usage(); + snprintf(buf, sizeof buf, "%s:list-forward", host_prefix); + char* forwards = adb_query(buf); + if (forwards == NULL) { + fprintf(stderr, "error: %s\n", adb_error()); + return 1; + } + printf("%s", forwards); + free(forwards); + return 0; + } + + // Implement forward --remove-all + else if (remove_all) { + if (argc != 1) + return usage(); + snprintf(buf, sizeof buf, "%s:killforward-all", host_prefix); + } + + // Implement forward --remove <local> + else if (remove) { + if (argc != 2) + return usage(); + snprintf(buf, sizeof buf, "%s:killforward:%s", host_prefix, argv[1]); + } + // Or implement one of: + // forward <local> <remote> + // forward --no-rebind <local> <remote> + else + { + if (argc != 3) + return usage(); + const char* command = no_rebind ? "forward:norebind:" : "forward"; + snprintf(buf, sizeof buf, "%s:%s:%s;%s", host_prefix, command, argv[1], argv[2]); + } + if(adb_command(buf)) { fprintf(stderr,"error: %s\n", adb_error()); return 1; |