am abf7cc97: am 13306d95: Merge "adb: Improve ADB\'s forward redirection management."

* commit 'abf7cc977e41540c45836d2fafd81606117f0399':
  adb: Improve ADB's forward redirection management.
This commit is contained in:
David 'Digit' Turner 2012-12-13 18:25:53 -08:00 committed by Android Git Automerger
commit 9bc6f20c61
3 changed files with 262 additions and 37 deletions

View File

@ -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:

177
adb/adb.c
View File

@ -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");
}

View File

@ -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();
if (serial) {
snprintf(buf, sizeof buf, "host-serial:%s:forward:%s;%s",serial, argv[1], argv[2]);
} else if (ttype == kTransportUsb) {
snprintf(buf, sizeof buf, "host-usb:forward:%s;%s", argv[1], argv[2]);
} else if (ttype == kTransportLocal) {
snprintf(buf, sizeof buf, "host-local:forward:%s;%s", argv[1], argv[2]);
} else {
snprintf(buf, sizeof buf, "host:forward:%s;%s", argv[1], argv[2]);
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(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
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;