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:
commit
9bc6f20c61
|
@ -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
177
adb/adb.c
|
@ -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");
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue