* commit 'c3358875169b920847a72428f4e8b8f09f7bdf05': adb: implement "adb reverse <local> <remote>"
This commit is contained in:
commit
972677557b
5 changed files with 198 additions and 101 deletions
|
|
@ -240,3 +240,20 @@ sync:
|
||||||
This starts the file synchronisation service, used to implement "adb push"
|
This starts the file synchronisation service, used to implement "adb push"
|
||||||
and "adb pull". Since this service is pretty complex, it will be detailed
|
and "adb pull". Since this service is pretty complex, it will be detailed
|
||||||
in a companion document named SYNC.TXT
|
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'.
|
||||||
|
|
|
||||||
221
adb/adb.c
221
adb/adb.c
|
|
@ -318,7 +318,18 @@ static size_t fill_connect_data(char *buf, size_t bufsize)
|
||||||
#endif
|
#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];
|
char header[9];
|
||||||
if (msglen > 0xffff)
|
if (msglen > 0xffff)
|
||||||
msglen = 0xffff;
|
msglen = 0xffff;
|
||||||
|
|
@ -1427,6 +1438,120 @@ int adb_main(int is_daemon, int server_port)
|
||||||
return 0;
|
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)
|
int handle_host_request(char *service, transport_type ttype, char* serial, int reply_fd, asocket *s)
|
||||||
{
|
{
|
||||||
atransport *transport = NULL;
|
atransport *transport = NULL;
|
||||||
|
|
@ -1547,97 +1672,9 @@ int handle_host_request(char *service, transport_type ttype, char* serial, int r
|
||||||
}
|
}
|
||||||
#endif // ADB_HOST
|
#endif // ADB_HOST
|
||||||
|
|
||||||
if(!strcmp(service,"list-forward")) {
|
int ret = handle_forward_request(service, ttype, serial, reply_fd);
|
||||||
// Create the list of forward redirections.
|
if (ret >= 0)
|
||||||
int buffer_size = format_listeners(NULL, 0);
|
return ret - 1;
|
||||||
// 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!strncmp(service,"get-state",strlen("get-state"))) {
|
if(!strncmp(service,"get-state",strlen("get-state"))) {
|
||||||
transport = acquire_one_transport(CS_ANY, ttype, serial, NULL);
|
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);
|
int create_jdwp_connection_fd(int jdwp_pid);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
int handle_forward_request(const char* service, transport_type ttype, char* serial, int reply_fd);
|
||||||
|
|
||||||
#if !ADB_HOST
|
#if !ADB_HOST
|
||||||
typedef enum {
|
typedef enum {
|
||||||
BACKUP,
|
BACKUP,
|
||||||
|
|
|
||||||
|
|
@ -136,6 +136,19 @@ void help()
|
||||||
" if <local> is already forwarded\n"
|
" if <local> is already forwarded\n"
|
||||||
" adb forward --remove <local> - remove a specific forward socket connection\n"
|
" adb forward --remove <local> - remove a specific forward socket connection\n"
|
||||||
" adb forward --remove-all - remove all forward socket connections\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 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"
|
" 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"
|
" - push this package file to the device and install it\n"
|
||||||
|
|
@ -1300,8 +1313,11 @@ top:
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!strcmp(argv[0], "forward")) {
|
if(!strcmp(argv[0], "forward") ||
|
||||||
|
!strcmp(argv[0], "reverse"))
|
||||||
|
{
|
||||||
char host_prefix[64];
|
char host_prefix[64];
|
||||||
|
char reverse = (char) !strcmp(argv[0], "reverse");
|
||||||
char remove = 0;
|
char remove = 0;
|
||||||
char remove_all = 0;
|
char remove_all = 0;
|
||||||
char list = 0;
|
char list = 0;
|
||||||
|
|
@ -1330,15 +1346,19 @@ top:
|
||||||
}
|
}
|
||||||
|
|
||||||
// Determine the <host-prefix> for this command.
|
// Determine the <host-prefix> for this command.
|
||||||
if (serial) {
|
if (reverse) {
|
||||||
snprintf(host_prefix, sizeof host_prefix, "host-serial:%s",
|
snprintf(host_prefix, sizeof host_prefix, "reverse");
|
||||||
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 {
|
} 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
|
// Implement forward --list
|
||||||
|
|
|
||||||
|
|
@ -141,6 +141,17 @@ cleanup:
|
||||||
adb_close(fd);
|
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
|
#endif
|
||||||
|
|
||||||
static int create_service_thread(void (*func)(int, void *), void *cookie)
|
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);
|
ret = create_service_thread(restart_tcp_service, (void *) (uintptr_t) port);
|
||||||
} else if(!strncmp(name, "usb:", 4)) {
|
} else if(!strncmp(name, "usb:", 4)) {
|
||||||
ret = create_service_thread(restart_usb_service, NULL);
|
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
|
#endif
|
||||||
}
|
}
|
||||||
if (ret >= 0) {
|
if (ret >= 0) {
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue