Merge "adb: Improve ADB's forward redirection management."
This commit is contained in:
commit
13306d95f6
3 changed files with 262 additions and 37 deletions
|
|
@ -117,7 +117,34 @@ host:<request>
|
||||||
|
|
||||||
or even any one of the local services described below.
|
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:
|
LOCAL SERVICES:
|
||||||
|
|
||||||
|
|
|
||||||
177
adb/adb.c
177
adb/adb.c
|
|
@ -722,24 +722,90 @@ int local_name_to_fd(const char *name)
|
||||||
return -1;
|
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;
|
alistener *l;
|
||||||
|
|
||||||
for (l = listener_list.next; l != &listener_list; l = l->next) {
|
for (l = listener_list.next; l != &listener_list; l = l->next) {
|
||||||
if (!strcmp(local_name, l->local_name) &&
|
if (!strcmp(local_name, l->local_name)) {
|
||||||
!strcmp(connect_to, l->connect_to) &&
|
listener_disconnect(l, l->transport);
|
||||||
l->transport && l->transport == transport) {
|
|
||||||
|
|
||||||
listener_disconnect(l, transport);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return -1;
|
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;
|
alistener *l;
|
||||||
|
|
||||||
|
|
@ -751,12 +817,17 @@ static int install_listener(const char *local_name, const char *connect_to, atra
|
||||||
|
|
||||||
/* can't repurpose a smartsocket */
|
/* can't repurpose a smartsocket */
|
||||||
if(l->connect_to[0] == '*') {
|
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);
|
cto = strdup(connect_to);
|
||||||
if(cto == 0) {
|
if(cto == 0) {
|
||||||
return -1;
|
return INSTALL_STATUS_INTERNAL_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
//printf("rebinding '%s' to '%s'\n", local_name, connect_to);
|
//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;
|
l->transport = transport;
|
||||||
add_transport_disconnect(l->transport, &l->disconnect);
|
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;
|
l->disconnect.func = listener_disconnect;
|
||||||
add_transport_disconnect(transport, &l->disconnect);
|
add_transport_disconnect(transport, &l->disconnect);
|
||||||
}
|
}
|
||||||
return 0;
|
return INSTALL_STATUS_OK;
|
||||||
|
|
||||||
nomem:
|
nomem:
|
||||||
fatal("cannot allocate listener");
|
fatal("cannot allocate listener");
|
||||||
return 0;
|
return INSTALL_STATUS_INTERNAL_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAVE_WIN32_PROC
|
#ifdef HAVE_WIN32_PROC
|
||||||
|
|
@ -1113,7 +1184,7 @@ int adb_main(int is_daemon, int server_port)
|
||||||
|
|
||||||
char local_name[30];
|
char local_name[30];
|
||||||
build_local_name(local_name, sizeof(local_name), server_port);
|
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);
|
exit(1);
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
|
|
@ -1180,7 +1251,7 @@ int adb_main(int is_daemon, int server_port)
|
||||||
} else {
|
} else {
|
||||||
char local_name[30];
|
char local_name[30];
|
||||||
build_local_name(local_name, sizeof(local_name), server_port);
|
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);
|
exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1474,24 +1545,63 @@ int handle_host_request(char *service, transport_type ttype, char* serial, int r
|
||||||
}
|
}
|
||||||
#endif // ADB_HOST
|
#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;
|
char *local, *remote, *err;
|
||||||
int r;
|
int r;
|
||||||
atransport *transport;
|
atransport *transport;
|
||||||
|
|
||||||
int createForward = strncmp(service,"kill",4);
|
int createForward = strncmp(service,"kill",4);
|
||||||
|
int no_rebind = 0;
|
||||||
|
|
||||||
local = service + (createForward ? 8 : 12);
|
local = strchr(service, ':') + 1;
|
||||||
remote = strchr(local,';');
|
|
||||||
if(remote == 0) {
|
// Handle forward:norebind:<local>... here
|
||||||
sendfailmsg(reply_fd, "malformed forward spec");
|
if (createForward && !strncmp(local, "norebind:", 9)) {
|
||||||
return 0;
|
no_rebind = 1;
|
||||||
|
local = strchr(local, ':') + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
*remote++ = 0;
|
remote = strchr(local,';');
|
||||||
if((local[0] == 0) || (remote[0] == 0) || (remote[0] == '*')){
|
|
||||||
sendfailmsg(reply_fd, "malformed forward spec");
|
if (createForward) {
|
||||||
return 0;
|
// 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);
|
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) {
|
if (createForward) {
|
||||||
r = install_listener(local, remote, transport);
|
r = install_listener(local, remote, transport, no_rebind);
|
||||||
} else {
|
} else {
|
||||||
r = remove_listener(local, remote, transport);
|
r = remove_listener(local, transport);
|
||||||
}
|
}
|
||||||
if(r == 0) {
|
if(r == 0) {
|
||||||
/* 1st OKAY is connect, 2nd OKAY is status */
|
/* 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) {
|
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 {
|
} else {
|
||||||
sendfailmsg(reply_fd, "cannot remove listener");
|
sendfailmsg(reply_fd, "cannot remove listener");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -112,6 +112,9 @@ void help()
|
||||||
" adb shell <command> - run remote shell command\n"
|
" adb shell <command> - run remote shell command\n"
|
||||||
" adb emu <command> - run emulator console command\n"
|
" adb emu <command> - run emulator console command\n"
|
||||||
" adb logcat [ <filter-spec> ] - View device log\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"
|
" adb forward <local> <remote> - forward socket connections\n"
|
||||||
" forward specs are one of: \n"
|
" forward specs are one of: \n"
|
||||||
" tcp:<port>\n"
|
" tcp:<port>\n"
|
||||||
|
|
@ -120,6 +123,11 @@ void help()
|
||||||
" localfilesystem:<unix domain socket name>\n"
|
" localfilesystem:<unix domain socket name>\n"
|
||||||
" dev:<character device name>\n"
|
" dev:<character device name>\n"
|
||||||
" jdwp:<process pid> (remote only)\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 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"
|
" 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"
|
" - push this package file to the device and install it\n"
|
||||||
|
|
@ -1223,16 +1231,85 @@ top:
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!strcmp(argv[0], "forward")) {
|
if(!strcmp(argv[0], "forward")) {
|
||||||
if(argc != 3) return usage();
|
char host_prefix[64];
|
||||||
if (serial) {
|
char remove = 0;
|
||||||
snprintf(buf, sizeof buf, "host-serial:%s:forward:%s;%s",serial, argv[1], argv[2]);
|
char remove_all = 0;
|
||||||
} else if (ttype == kTransportUsb) {
|
char list = 0;
|
||||||
snprintf(buf, sizeof buf, "host-usb:forward:%s;%s", argv[1], argv[2]);
|
char no_rebind = 0;
|
||||||
} else if (ttype == kTransportLocal) {
|
|
||||||
snprintf(buf, sizeof buf, "host-local:forward:%s;%s", argv[1], argv[2]);
|
// Parse options here.
|
||||||
} else {
|
while (argc > 1 && argv[1][0] == '-') {
|
||||||
snprintf(buf, sizeof buf, "host:forward:%s;%s", argv[1], argv[2]);
|
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)) {
|
if(adb_command(buf)) {
|
||||||
fprintf(stderr,"error: %s\n", adb_error());
|
fprintf(stderr,"error: %s\n", adb_error());
|
||||||
return 1;
|
return 1;
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue