mirror of
https://github.com/Genymobile/scrcpy.git
synced 2025-08-03 22:58:51 +00:00
Added complicated reverse tunnelling.
This commit is contained in:
parent
3bdd6acb53
commit
fc2961e21e
7 changed files with 96 additions and 44 deletions
|
@ -103,15 +103,22 @@ show_adb_err_msg(enum process_result err, const char *const argv[]) {
|
||||||
}
|
}
|
||||||
|
|
||||||
process_t
|
process_t
|
||||||
ssh_execute(const char *endpoint, const char *const adb_cmd[], size_t len) {
|
ssh_execute(const char *endpoint, const char *const ssh_cmd[], size_t len,
|
||||||
const char *cmd[len + 3];
|
const char *const prefix_cmd[], size_t prefix_cmd_len,
|
||||||
int i = 2;
|
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;
|
process_t process;
|
||||||
cmd[0] = "ssh";
|
|
||||||
cmd[1] = endpoint;
|
|
||||||
|
|
||||||
memcpy(&cmd[i], adb_cmd, len * sizeof(const char *));
|
cmd[i++] = "ssh";
|
||||||
cmd[len + i] = NULL;
|
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);
|
enum process_result r = cmd_execute(cmd, &process);
|
||||||
if (r != PROCESS_SUCCESS) {
|
if (r != PROCESS_SUCCESS) {
|
||||||
show_adb_err_msg(r, cmd);
|
show_adb_err_msg(r, cmd);
|
||||||
|
|
|
@ -58,7 +58,9 @@ bool
|
||||||
cmd_simple_wait(process_t pid, exit_code_t *exit_code);
|
cmd_simple_wait(process_t pid, exit_code_t *exit_code);
|
||||||
|
|
||||||
process_t
|
process_t
|
||||||
ssh_execute(const char *serial, const char *const adb_cmd[], size_t len);
|
ssh_execute(const char *serial, 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
|
process_t
|
||||||
adb_execute(const char *serial, const char *const adb_cmd[], size_t len);
|
adb_execute(const char *serial, const char *const adb_cmd[], size_t len);
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
#include "util/str_util.h"
|
#include "util/str_util.h"
|
||||||
|
|
||||||
#define SOCKET_NAME "scrcpy"
|
#define SOCKET_NAME "scrcpy"
|
||||||
#define SSH_SOCKET_NAME "/data/local/tmp/scrcpy"
|
#define SSH_SOCKET_NAME "/dev/socket/scrcpy"
|
||||||
#define SERVER_FILENAME "scrcpy-server"
|
#define SERVER_FILENAME "scrcpy-server"
|
||||||
|
|
||||||
#define DEFAULT_SERVER_PATH PREFIX "/share/scrcpy/" SERVER_FILENAME
|
#define DEFAULT_SERVER_PATH PREFIX "/share/scrcpy/" SERVER_FILENAME
|
||||||
|
@ -104,6 +104,17 @@ push_server(const char *serial) {
|
||||||
return process_check_success(process, "adb push");
|
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
|
static bool
|
||||||
enable_tunnel_reverse(const char *serial, uint16_t local_port) {
|
enable_tunnel_reverse(const char *serial, uint16_t local_port) {
|
||||||
process_t process = adb_reverse(serial, SOCKET_NAME, local_port);
|
process_t process = adb_reverse(serial, SOCKET_NAME, local_port);
|
||||||
|
@ -295,7 +306,6 @@ execute_server(struct server *server, const struct server_params *params) {
|
||||||
params->show_touches ? "true" : "false",
|
params->show_touches ? "true" : "false",
|
||||||
params->stay_awake ? "true" : "false",
|
params->stay_awake ? "true" : "false",
|
||||||
params->codec_options ? params->codec_options : "-",
|
params->codec_options ? params->codec_options : "-",
|
||||||
params->use_ssh ? "true" : "false",
|
|
||||||
};
|
};
|
||||||
#ifdef SERVER_DEBUGGER
|
#ifdef SERVER_DEBUGGER
|
||||||
LOGI("Server debugger waiting for a client on device port "
|
LOGI("Server debugger waiting for a client on device port "
|
||||||
|
@ -309,7 +319,46 @@ execute_server(struct server *server, const struct server_params *params) {
|
||||||
// Then click on "Debug"
|
// Then click on "Debug"
|
||||||
#endif
|
#endif
|
||||||
if (params->use_ssh)
|
if (params->use_ssh)
|
||||||
return ssh_execute(params->ssh_endpoint, cmd, sizeof(cmd) / sizeof(cmd[0]));
|
{
|
||||||
|
char *tunnel_desc = SDL_strdup(SSH_SOCKET_NAME ":localhost:12345");
|
||||||
|
const char *const ssh_options[] = {
|
||||||
|
"-o", "ExitOnForwardFailure=yes",
|
||||||
|
"-R", tunnel_desc,
|
||||||
|
};
|
||||||
|
|
||||||
|
const char *const prefix_cmd[] = {
|
||||||
|
"/data/ssh/root/socat",
|
||||||
|
"abstract-listen:" SOCKET_NAME ",fork",
|
||||||
|
"unix-connect:" SSH_SOCKET_NAME,
|
||||||
|
"&",
|
||||||
|
};
|
||||||
|
|
||||||
|
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;
|
||||||
|
snprintf(tunnel_desc + strlen(tunnel_desc) - 5, 6, "%d", port);
|
||||||
|
|
||||||
|
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
|
else
|
||||||
return adb_execute(server->serial, cmd, sizeof(cmd) / sizeof(cmd[0]));
|
return adb_execute(server->serial, cmd, sizeof(cmd) / sizeof(cmd[0]));
|
||||||
}
|
}
|
||||||
|
@ -390,10 +439,15 @@ server_start(struct server *server, const char *serial,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
server->use_ssh = params->use_ssh;
|
||||||
|
|
||||||
if (!push_server(serial)) {
|
if (!push_server(serial)) {
|
||||||
goto error1;
|
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,
|
if (!params->use_ssh && !enable_tunnel_any_port(server, params->port_range,
|
||||||
params->force_adb_forward)) {
|
params->force_adb_forward)) {
|
||||||
goto error1;
|
goto error1;
|
||||||
|
@ -419,21 +473,21 @@ server_start(struct server *server, const char *serial,
|
||||||
goto error2;
|
goto error2;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!params->use_ssh)
|
server->tunnel_enabled = true;
|
||||||
server->tunnel_enabled = true;
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
error2:
|
error2:
|
||||||
if (!params->use_ssh) {
|
if (!server->tunnel_forward) {
|
||||||
if (!server->tunnel_forward) {
|
bool was_closed =
|
||||||
bool was_closed =
|
atomic_flag_test_and_set(&server->server_socket_closed);
|
||||||
atomic_flag_test_and_set(&server->server_socket_closed);
|
// the thread is not started, the flag could not be already set
|
||||||
// the thread is not started, the flag could not be already set
|
assert(!was_closed);
|
||||||
assert(!was_closed);
|
(void) was_closed;
|
||||||
(void) was_closed;
|
close_socket(server->server_socket);
|
||||||
close_socket(server->server_socket);
|
}
|
||||||
}
|
|
||||||
|
if (!server->use_ssh) {
|
||||||
disable_tunnel(server);
|
disable_tunnel(server);
|
||||||
}
|
}
|
||||||
error1:
|
error1:
|
||||||
|
@ -480,7 +534,8 @@ server_connect_to(struct server *server) {
|
||||||
|
|
||||||
if (server->tunnel_enabled) {
|
if (server->tunnel_enabled) {
|
||||||
// we don't need the adb tunnel anymore
|
// we don't need the adb tunnel anymore
|
||||||
disable_tunnel(server); // ignore failure
|
if (!server->use_ssh)
|
||||||
|
disable_tunnel(server); // ignore failure
|
||||||
server->tunnel_enabled = false;
|
server->tunnel_enabled = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -504,7 +559,7 @@ server_stop(struct server *server) {
|
||||||
|
|
||||||
cmd_terminate(server->process);
|
cmd_terminate(server->process);
|
||||||
|
|
||||||
if (server->tunnel_enabled) {
|
if (server->tunnel_enabled && !server->use_ssh) {
|
||||||
// ignore failure
|
// ignore failure
|
||||||
disable_tunnel(server);
|
disable_tunnel(server);
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,6 +25,7 @@ struct server {
|
||||||
uint16_t local_port; // selected from port_range
|
uint16_t local_port; // selected from port_range
|
||||||
bool tunnel_enabled;
|
bool tunnel_enabled;
|
||||||
bool tunnel_forward; // use "adb forward" instead of "adb reverse"
|
bool tunnel_forward; // use "adb forward" instead of "adb reverse"
|
||||||
|
bool use_ssh;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define SERVER_INITIALIZER { \
|
#define SERVER_INITIALIZER { \
|
||||||
|
@ -42,6 +43,7 @@ struct server {
|
||||||
.local_port = 0, \
|
.local_port = 0, \
|
||||||
.tunnel_enabled = false, \
|
.tunnel_enabled = false, \
|
||||||
.tunnel_forward = false, \
|
.tunnel_forward = false, \
|
||||||
|
.use_ssh = false, \
|
||||||
}
|
}
|
||||||
|
|
||||||
struct server_params {
|
struct server_params {
|
||||||
|
|
|
@ -16,7 +16,6 @@ public final class DesktopConnection implements Closeable {
|
||||||
private static final int DEVICE_NAME_FIELD_LENGTH = 64;
|
private static final int DEVICE_NAME_FIELD_LENGTH = 64;
|
||||||
|
|
||||||
private static final String SOCKET_NAME = "scrcpy";
|
private static final String SOCKET_NAME = "scrcpy";
|
||||||
private static final String SSH_SOCKET_NAME = "/data/local/tmp/scrcpy";
|
|
||||||
|
|
||||||
private final LocalSocket videoSocket;
|
private final LocalSocket videoSocket;
|
||||||
private final FileDescriptor videoFd;
|
private final FileDescriptor videoFd;
|
||||||
|
@ -42,11 +41,11 @@ public final class DesktopConnection implements Closeable {
|
||||||
return localSocket;
|
return localSocket;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static DesktopConnection open(Device device, boolean tunnelForward, boolean sshMode) throws IOException {
|
public static DesktopConnection open(Device device, boolean tunnelForward) throws IOException {
|
||||||
LocalSocket videoSocket;
|
LocalSocket videoSocket;
|
||||||
LocalSocket controlSocket;
|
LocalSocket controlSocket;
|
||||||
if (tunnelForward) {
|
if (tunnelForward) {
|
||||||
LocalServerSocket localServerSocket = new LocalServerSocket(sshMode ? SSH_SOCKET_NAME : SOCKET_NAME);
|
LocalServerSocket localServerSocket = new LocalServerSocket(SOCKET_NAME);
|
||||||
try {
|
try {
|
||||||
videoSocket = localServerSocket.accept();
|
videoSocket = localServerSocket.accept();
|
||||||
// send one byte so the client may read() to detect a connection error
|
// send one byte so the client may read() to detect a connection error
|
||||||
|
@ -61,9 +60,9 @@ public final class DesktopConnection implements Closeable {
|
||||||
localServerSocket.close();
|
localServerSocket.close();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
videoSocket = connect(sshMode ? SSH_SOCKET_NAME : SOCKET_NAME);
|
videoSocket = connect(SOCKET_NAME);
|
||||||
try {
|
try {
|
||||||
controlSocket = connect(sshMode ? SSH_SOCKET_NAME : SOCKET_NAME);
|
controlSocket = connect(SOCKET_NAME);
|
||||||
} catch (IOException | RuntimeException e) {
|
} catch (IOException | RuntimeException e) {
|
||||||
videoSocket.close();
|
videoSocket.close();
|
||||||
throw e;
|
throw e;
|
||||||
|
|
|
@ -16,7 +16,6 @@ public class Options {
|
||||||
private boolean showTouches;
|
private boolean showTouches;
|
||||||
private boolean stayAwake;
|
private boolean stayAwake;
|
||||||
private String codecOptions;
|
private String codecOptions;
|
||||||
private boolean sshMode;
|
|
||||||
|
|
||||||
public Ln.Level getLogLevel() {
|
public Ln.Level getLogLevel() {
|
||||||
return logLevel;
|
return logLevel;
|
||||||
|
@ -121,12 +120,4 @@ public class Options {
|
||||||
public void setCodecOptions(String codecOptions) {
|
public void setCodecOptions(String codecOptions) {
|
||||||
this.codecOptions = codecOptions;
|
this.codecOptions = codecOptions;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isSshMode() {
|
|
||||||
return sshMode;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setSshMode(boolean sshMode) {
|
|
||||||
this.sshMode = sshMode;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,9 +52,8 @@ public final class Server {
|
||||||
CleanUp.configure(mustDisableShowTouchesOnCleanUp, restoreStayOn, true);
|
CleanUp.configure(mustDisableShowTouchesOnCleanUp, restoreStayOn, true);
|
||||||
|
|
||||||
boolean tunnelForward = options.isTunnelForward();
|
boolean tunnelForward = options.isTunnelForward();
|
||||||
boolean sshMode = options.isSshMode();
|
|
||||||
|
|
||||||
try (DesktopConnection connection = DesktopConnection.open(device, tunnelForward, sshMode)) {
|
try (DesktopConnection connection = DesktopConnection.open(device, tunnelForward)) {
|
||||||
ScreenEncoder screenEncoder = new ScreenEncoder(options.getSendFrameMeta(), options.getBitRate(), options.getMaxFps(), codecOptions);
|
ScreenEncoder screenEncoder = new ScreenEncoder(options.getSendFrameMeta(), options.getBitRate(), options.getMaxFps(), codecOptions);
|
||||||
|
|
||||||
if (options.getControl()) {
|
if (options.getControl()) {
|
||||||
|
@ -121,7 +120,7 @@ public final class Server {
|
||||||
"The server version (" + BuildConfig.VERSION_NAME + ") does not match the client " + "(" + clientVersion + ")");
|
"The server version (" + BuildConfig.VERSION_NAME + ") does not match the client " + "(" + clientVersion + ")");
|
||||||
}
|
}
|
||||||
|
|
||||||
final int expectedParameters = 15;
|
final int expectedParameters = 14;
|
||||||
if (args.length != expectedParameters) {
|
if (args.length != expectedParameters) {
|
||||||
throw new IllegalArgumentException("Expecting " + expectedParameters + " parameters");
|
throw new IllegalArgumentException("Expecting " + expectedParameters + " parameters");
|
||||||
}
|
}
|
||||||
|
@ -168,9 +167,6 @@ public final class Server {
|
||||||
String codecOptions = args[13];
|
String codecOptions = args[13];
|
||||||
options.setCodecOptions(codecOptions);
|
options.setCodecOptions(codecOptions);
|
||||||
|
|
||||||
boolean sshMode = Boolean.parseBoolean(args[14]);
|
|
||||||
options.setSshMode(sshMode);
|
|
||||||
|
|
||||||
return options;
|
return options;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue