This commit is contained in:
Vladimir Chebotarev 2020-12-23 10:41:40 +08:00 committed by GitHub
commit 79e003ac18
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 293 additions and 13 deletions

3
.gitmodules vendored Normal file
View file

@ -0,0 +1,3 @@
[submodule "abstractcat"]
path = abstractcat
url = https://github.com/excitoon/abstractcat

1
abstractcat Submodule

@ -0,0 +1 @@
Subproject commit f232a5a7d590089721c64b5257198064bdf9fab7

View file

@ -651,6 +651,8 @@ guess_record_format(const char *filename) {
#define OPT_DISABLE_SCREENSAVER 1020
#define OPT_SHORTCUT_MOD 1021
#define OPT_NO_KEY_REPEAT 1022
#define OPT_USE_SSH 1024
#define OPT_SSH_ENDPOINT 1025
bool
scrcpy_parse_args(struct scrcpy_cli_args *args, int argc, char *argv[]) {
@ -686,6 +688,7 @@ scrcpy_parse_args(struct scrcpy_cli_args *args, int argc, char *argv[]) {
{"serial", required_argument, NULL, 's'},
{"shortcut-mod", required_argument, NULL, OPT_SHORTCUT_MOD},
{"show-touches", no_argument, NULL, 't'},
{"ssh-endpoint", required_argument, NULL, OPT_SSH_ENDPOINT},
{"stay-awake", no_argument, NULL, 'w'},
{"turn-screen-off", no_argument, NULL, 'S'},
{"verbosity", required_argument, NULL, 'V'},
@ -697,6 +700,7 @@ scrcpy_parse_args(struct scrcpy_cli_args *args, int argc, char *argv[]) {
{"window-height", required_argument, NULL, OPT_WINDOW_HEIGHT},
{"window-borderless", no_argument, NULL,
OPT_WINDOW_BORDERLESS},
{"use-ssh", no_argument, NULL, OPT_USE_SSH},
{NULL, 0, NULL, 0 },
};
@ -799,6 +803,9 @@ scrcpy_parse_args(struct scrcpy_cli_args *args, int argc, char *argv[]) {
case OPT_WINDOW_TITLE:
opts->window_title = optarg;
break;
case OPT_SSH_ENDPOINT:
opts->ssh_endpoint = optarg;
break;
case OPT_WINDOW_X:
if (!parse_window_position(optarg, &opts->window_x)) {
return false;
@ -856,6 +863,9 @@ scrcpy_parse_args(struct scrcpy_cli_args *args, int argc, char *argv[]) {
return false;
}
break;
case OPT_USE_SSH:
opts->use_ssh = true;
break;
default:
// getopt prints the error message on stderr
return false;

View file

@ -102,6 +102,49 @@ show_adb_err_msg(enum process_result err, const char *const argv[]) {
}
}
process_t
scp_execute(const char *const scp_cmd[], size_t len) {
const char *cmd[len + 2];
unsigned i = 0;
process_t process;
cmd[i++] = "scp";
memcpy(&cmd[i], scp_cmd, len * sizeof(const char *));
i += len;
cmd[i] = NULL;
enum process_result r = cmd_execute(cmd, &process);
if (r != PROCESS_SUCCESS) {
show_adb_err_msg(r, cmd);
return PROCESS_NONE;
}
return process;
}
process_t
ssh_execute(const char *endpoint, const char *const ssh_cmd[], size_t len,
const char *const prefix_cmd[], size_t prefix_cmd_len,
const char *const ssh_options[], size_t ssh_options_len) {
const char *cmd[len + prefix_cmd_len + ssh_options_len + 3];
unsigned i = 0;
process_t process;
cmd[i++] = "ssh";
memcpy(&cmd[i], ssh_options, ssh_options_len * sizeof(const char *));
i += ssh_options_len;
cmd[i++] = endpoint;
memcpy(&cmd[i], prefix_cmd, prefix_cmd_len * sizeof(const char *));
i += prefix_cmd_len;
memcpy(&cmd[i], ssh_cmd, len * sizeof(const char *));
i += len;
cmd[i] = NULL;
enum process_result r = cmd_execute(cmd, &process);
if (r != PROCESS_SUCCESS) {
show_adb_err_msg(r, cmd);
return PROCESS_NONE;
}
return process;
}
process_t
adb_execute(const char *serial, const char *const adb_cmd[], size_t len) {
const char *cmd[len + 4];
@ -164,6 +207,38 @@ adb_reverse_remove(const char *serial, const char *device_socket_name) {
return adb_execute(serial, adb_cmd, ARRAY_LEN(adb_cmd));
}
process_t
ssh_push(const char *endpoint, const char *local, const char *remote) {
#ifdef __WINDOWS__
// Windows will parse the string, so the paths must be quoted
// (see sys/win/command.c)
local = strquote(local);
if (!local) {
return PROCESS_NONE;
}
remote = strquote(remote);
if (!remote) {
SDL_free((void *) local);
return PROCESS_NONE;
}
#endif
char * destination = (char *) SDL_malloc(strlen(remote) + strlen(endpoint) + 2);
strcpy(destination, endpoint);
strcat(destination, ":");
strcat(destination, remote);
const char *const scp_cmd[] = {local, destination};
process_t proc = scp_execute(scp_cmd, ARRAY_LEN(scp_cmd));
#ifdef __WINDOWS__
SDL_free((void *) remote);
SDL_free((void *) local);
#endif
SDL_free((void *) destination);
return proc;
}
process_t
adb_push(const char *serial, const char *local, const char *remote) {
#ifdef __WINDOWS__

View file

@ -57,6 +57,14 @@ cmd_terminate(process_t pid);
bool
cmd_simple_wait(process_t pid, exit_code_t *exit_code);
process_t
scp_execute(const char *const ssh_cmd[], size_t len);
process_t
ssh_execute(const char *endpoint, const char *const ssh_cmd[], size_t len,
const char *const prefix_cmd[], size_t prefix_cmd_len,
const char *const ssh_options[], size_t ssh_options_len);
process_t
adb_execute(const char *serial, const char *const adb_cmd[], size_t len);
@ -74,6 +82,9 @@ adb_reverse(const char *serial, const char *device_socket_name,
process_t
adb_reverse_remove(const char *serial, const char *device_socket_name);
process_t
ssh_push(const char *endpoint, const char *local, const char *remote);
process_t
adb_push(const char *serial, const char *local, const char *remote);

View file

@ -319,6 +319,8 @@ scrcpy(const struct scrcpy_options *options) {
.stay_awake = options->stay_awake,
.codec_options = options->codec_options,
.force_adb_forward = options->force_adb_forward,
.use_ssh = options->use_ssh,
.ssh_endpoint = options->ssh_endpoint,
};
if (!server_start(&server, options->serial, &params)) {
return false;

View file

@ -51,6 +51,7 @@ struct scrcpy_options {
const char *push_target;
const char *render_driver;
const char *codec_options;
const char *ssh_endpoint;
enum sc_log_level log_level;
enum sc_record_format record_format;
struct sc_port_range port_range;
@ -79,6 +80,7 @@ struct scrcpy_options {
bool force_adb_forward;
bool disable_screensaver;
bool forward_key_repeat;
bool use_ssh;
};
#define SCRCPY_OPTIONS_DEFAULT { \
@ -123,6 +125,8 @@ struct scrcpy_options {
.force_adb_forward = false, \
.disable_screensaver = false, \
.forward_key_repeat = true, \
.use_ssh = false, \
.ssh_endpoint = NULL, \
}
bool

View file

@ -16,11 +16,18 @@
#include "util/str_util.h"
#define SOCKET_NAME "scrcpy"
#define SSH_SOCKET_NAME "/dev/socket/scrcpy"
#define SERVER_FILENAME "scrcpy-server"
#define ABSTRACTCAT_FILENAME "abstractcat"
#define DEFAULT_SERVER_PATH PREFIX "/share/scrcpy/" SERVER_FILENAME
#define DEVICE_SERVER_PATH "/data/local/tmp/scrcpy-server.jar"
#define DEFAULT_ABSTRACTCAT_PATH PREFIX "/share/scrcpy/" ABSTRACTCAT_FILENAME
#define DEVICE_ABSTRACTCAT_PATH "/data/local/tmp/" ABSTRACTCAT_FILENAME
static void close_socket(socket_t socket);
static char *
get_server_path(void) {
#ifdef __WINDOWS__
@ -87,8 +94,90 @@ get_server_path(void) {
#endif
}
static char *
get_abstractcat_path(void) {
#ifdef __WINDOWS__
const wchar_t *abstractcat_path_env = _wgetenv(L"SCRCPY_ABSTRACTCAT_PATH");
#else
const char *abstractcat_path_env = getenv("SCRCPY_ABSTRACTCAT_PATH");
#endif
if (abstractcat_path_env) {
// if the envvar is set, use it
#ifdef __WINDOWS__
char *abstractcat_path = utf8_from_wide_char(abstractcat_path_env);
#else
char *abstractcat_path = SDL_strdup(abstractcat_path_env);
#endif
if (!abstractcat_path) {
LOGE("Could not allocate memory");
return NULL;
}
LOGD("Using SCRCPY_ABSTRACTCAT_PATH: %s", abstractcat_path);
return abstractcat_path;
}
#ifndef PORTABLE
LOGD("Using abstractcat: " DEFAULT_ABSTRACTCAT_PATH);
char *abstractcat_path = SDL_strdup(DEFAULT_ABSTRACTCAT_PATH);
if (!abstractcat_path) {
LOGE("Could not allocate memory");
return NULL;
}
// the absolute path is hardcoded
return abstractcat_path;
#else
// use scrcpy-server in the same directory as the executable
char *executable_path = get_executable_path();
if (!executable_path) {
LOGE("Could not get executable path, "
"using " ABSTRACTCAT_FILENAME " from current directory");
// not found, use current directory
return ABSTRACTCAT_FILENAME;
}
char *dir = dirname(executable_path);
size_t dirlen = strlen(dir);
// sizeof(ABSTRACTCAT_FILENAME) gives statically the size including the null byte
size_t len = dirlen + 1 + sizeof(ABSTRACTCAT_FILENAME);
char *abstractcat_path = SDL_malloc(len);
if (!abstractcat_path) {
LOGE("Could not alloc abstractcat path string, "
"using " ABSTRACTCAT_FILENAME " from current directory");
SDL_free(executable_path);
return ABSTRACTCAT_FILENAME;
}
memcpy(abstractcat_path, dir, dirlen);
abstractcat_path[dirlen] = PATH_SEPARATOR;
memcpy(&abstractcat_path[dirlen + 1], ABSTRACTCAT_FILENAME, sizeof(ABSTRACTCAT_FILENAME));
// the final null byte has been copied with ABSTRACTCAT_FILENAME
SDL_free(executable_path);
LOGD("Using abstractcat (portable): %s", abstractcat_path);
return abstractcat_path;
#endif
}
static bool
push_server(const char *serial) {
push_abstractcat(const struct server_params *params) {
char *abstractcat_path = get_abstractcat_path();
if (!abstractcat_path) {
return false;
}
if (!is_regular_file(abstractcat_path)) {
LOGE("'%s' does not exist or is not a regular file\n", abstractcat_path);
SDL_free(abstractcat_path);
return false;
}
process_t process = ssh_push(params->ssh_endpoint, abstractcat_path, DEVICE_ABSTRACTCAT_PATH);
SDL_free(abstractcat_path);
return process_check_success(process, "scp");
}
static bool
push_server(const char *serial, const struct server_params *params) {
char *server_path = get_server_path();
if (!server_path) {
return false;
@ -98,11 +187,26 @@ push_server(const char *serial) {
SDL_free(server_path);
return false;
}
process_t process = adb_push(serial, server_path, DEVICE_SERVER_PATH);
process_t process;
if (params->use_ssh)
process = ssh_push(params->ssh_endpoint, server_path, DEVICE_SERVER_PATH);
else
process = adb_push(serial, server_path, DEVICE_SERVER_PATH);
SDL_free(server_path);
return process_check_success(process, "adb push");
}
static bool prepare_ssh_socket_path(const struct server_params *params) {
const char *const cmd[] = {
"rm",
"-f",
SSH_SOCKET_NAME,
};
process_t process = ssh_execute(params->ssh_endpoint, cmd, sizeof(cmd) / sizeof(cmd[0]),
NULL, 0, NULL, 0);
return process_check_success(process, "ssh rm -f " SSH_SOCKET_NAME);
}
static bool
enable_tunnel_reverse(const char *serial, uint16_t local_port) {
process_t process = adb_reverse(serial, SOCKET_NAME, local_port);
@ -264,9 +368,9 @@ execute_server(struct server *server, const struct server_params *params) {
sprintf(lock_video_orientation_string, "%"PRIi8, params->lock_video_orientation);
sprintf(display_id_string, "%"PRIu16, params->display_id);
const char *const cmd[] = {
"shell",
params->use_ssh ? "ANDROID_DATA=/data" : "shell",
"CLASSPATH=" DEVICE_SERVER_PATH,
"app_process",
"/system/bin/app_process",
#ifdef SERVER_DEBUGGER
# define SERVER_DEBUGGER_PORT "5005"
# ifdef SERVER_DEBUGGER_METHOD_NEW
@ -286,7 +390,7 @@ execute_server(struct server *server, const struct server_params *params) {
bit_rate_string,
max_fps_string,
lock_video_orientation_string,
server->tunnel_forward ? "true" : "false",
server->tunnel_forward || params->force_adb_forward ? "true" : "false",
params->crop ? params->crop : "-",
"true", // always send frame meta (packet boundaries + timestamp)
params->control ? "true" : "false",
@ -306,7 +410,59 @@ execute_server(struct server *server, const struct server_params *params) {
// Port: 5005
// Then click on "Debug"
#endif
return adb_execute(server->serial, cmd, sizeof(cmd) / sizeof(cmd[0]));
if (params->use_ssh)
{
for (uint16_t port = server->port_range.first;;) {
server->server_socket = listen_on_port(port);
if (server->server_socket == INVALID_SOCKET) {
if (port < server->port_range.last) {
LOGW("Could not listen on port %" PRIu16", retrying on %" PRIu16,
port, (uint16_t) (port + 1));
port++;
continue;
}
if (server->port_range.first == server->port_range.last) {
LOGE("Could not listen on port %" PRIu16, server->port_range.first);
} else {
LOGE("Could not listen on any port in range %" PRIu16 ":%" PRIu16,
server->port_range.first, server->port_range.last);
}
return PROCESS_NONE;
}
server->local_port = port;
char *tunnel_desc = SDL_strdup(SSH_SOCKET_NAME ":localhost:12345");
if (params->force_adb_forward)
sprintf(tunnel_desc, "localhost:%d:" SSH_SOCKET_NAME, port);
else
sprintf(tunnel_desc, SSH_SOCKET_NAME ":localhost:%d", port);
const char *const ssh_options[] = {
"-o", "ExitOnForwardFailure=yes",
params->force_adb_forward ? "-L" : "-R", tunnel_desc,
};
const char *const prefix_cmd[] = {
DEVICE_ABSTRACTCAT_PATH,
params->force_adb_forward ? SSH_SOCKET_NAME : "@" SOCKET_NAME, // Source.
params->force_adb_forward ? "@" SOCKET_NAME : SSH_SOCKET_NAME, // Destination.
"2", // Maximum connections to forward.
};
if (params->force_adb_forward) {
close_socket(server->server_socket);
server->server_socket = INVALID_SOCKET;
server->tunnel_forward = true;
}
return ssh_execute(params->ssh_endpoint, cmd, sizeof(cmd) / sizeof(cmd[0]),
prefix_cmd, sizeof(prefix_cmd) / sizeof(prefix_cmd[0]),
ssh_options, sizeof(ssh_options) / sizeof(ssh_options[0]));
}
}
else
return adb_execute(server->serial, cmd, sizeof(cmd) / sizeof(cmd[0]));
}
static socket_t
@ -385,11 +541,19 @@ server_start(struct server *server, const char *serial,
}
}
if (!push_server(serial)) {
server->use_ssh = params->use_ssh;
if (!push_server(serial, params)) {
goto error1;
}
if (!enable_tunnel_any_port(server, params->port_range,
if (params->use_ssh && !push_abstractcat(params))
goto error1;
if (params->use_ssh && !prepare_ssh_socket_path(params))
goto error1;
if (!params->use_ssh && !enable_tunnel_any_port(server, params->port_range,
params->force_adb_forward)) {
goto error1;
}
@ -427,7 +591,10 @@ error2:
(void) was_closed;
close_socket(server->server_socket);
}
disable_tunnel(server);
if (!server->use_ssh) {
disable_tunnel(server);
}
error1:
SDL_free(server->serial);
return false;
@ -470,9 +637,12 @@ server_connect_to(struct server *server) {
}
}
// we don't need the adb tunnel anymore
disable_tunnel(server); // ignore failure
server->tunnel_enabled = false;
if (server->tunnel_enabled) {
// we don't need the adb tunnel anymore
if (!server->use_ssh)
disable_tunnel(server); // ignore failure
server->tunnel_enabled = false;
}
return true;
}
@ -494,7 +664,7 @@ server_stop(struct server *server) {
cmd_terminate(server->process);
if (server->tunnel_enabled) {
if (server->tunnel_enabled && !server->use_ssh) {
// ignore failure
disable_tunnel(server);
}

View file

@ -25,6 +25,7 @@ struct server {
uint16_t local_port; // selected from port_range
bool tunnel_enabled;
bool tunnel_forward; // use "adb forward" instead of "adb reverse"
bool use_ssh;
};
#define SERVER_INITIALIZER { \
@ -42,12 +43,14 @@ struct server {
.local_port = 0, \
.tunnel_enabled = false, \
.tunnel_forward = false, \
.use_ssh = false, \
}
struct server_params {
enum sc_log_level log_level;
const char *crop;
const char *codec_options;
const char *ssh_endpoint;
struct sc_port_range port_range;
uint16_t max_size;
uint32_t bit_rate;
@ -58,6 +61,7 @@ struct server_params {
bool show_touches;
bool stay_awake;
bool force_adb_forward;
bool use_ssh;
};
// init default values