Added complicated reverse tunnelling.

This commit is contained in:
Vladimir Chebotarev 2020-09-06 18:59:52 +03:00
parent 3bdd6acb53
commit fc2961e21e
7 changed files with 96 additions and 44 deletions

View file

@ -103,15 +103,22 @@ show_adb_err_msg(enum process_result err, const char *const argv[]) {
}
process_t
ssh_execute(const char *endpoint, const char *const adb_cmd[], size_t len) {
const char *cmd[len + 3];
int i = 2;
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[0] = "ssh";
cmd[1] = endpoint;
memcpy(&cmd[i], adb_cmd, len * sizeof(const char *));
cmd[len + i] = NULL;
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);

View file

@ -58,7 +58,9 @@ bool
cmd_simple_wait(process_t pid, exit_code_t *exit_code);
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
adb_execute(const char *serial, const char *const adb_cmd[], size_t len);

View file

@ -16,7 +16,7 @@
#include "util/str_util.h"
#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 DEFAULT_SERVER_PATH PREFIX "/share/scrcpy/" SERVER_FILENAME
@ -104,6 +104,17 @@ push_server(const char *serial) {
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);
@ -295,7 +306,6 @@ execute_server(struct server *server, const struct server_params *params) {
params->show_touches ? "true" : "false",
params->stay_awake ? "true" : "false",
params->codec_options ? params->codec_options : "-",
params->use_ssh ? "true" : "false",
};
#ifdef SERVER_DEBUGGER
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"
#endif
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
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)) {
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;
@ -419,21 +473,21 @@ server_start(struct server *server, const char *serial,
goto error2;
}
if (!params->use_ssh)
server->tunnel_enabled = true;
server->tunnel_enabled = true;
return true;
error2:
if (!params->use_ssh) {
if (!server->tunnel_forward) {
bool was_closed =
atomic_flag_test_and_set(&server->server_socket_closed);
// the thread is not started, the flag could not be already set
assert(!was_closed);
(void) was_closed;
close_socket(server->server_socket);
}
if (!server->tunnel_forward) {
bool was_closed =
atomic_flag_test_and_set(&server->server_socket_closed);
// the thread is not started, the flag could not be already set
assert(!was_closed);
(void) was_closed;
close_socket(server->server_socket);
}
if (!server->use_ssh) {
disable_tunnel(server);
}
error1:
@ -480,7 +534,8 @@ server_connect_to(struct server *server) {
if (server->tunnel_enabled) {
// 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;
}
@ -504,7 +559,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,6 +43,7 @@ struct server {
.local_port = 0, \
.tunnel_enabled = false, \
.tunnel_forward = false, \
.use_ssh = false, \
}
struct server_params {

View file

@ -16,7 +16,6 @@ public final class DesktopConnection implements Closeable {
private static final int DEVICE_NAME_FIELD_LENGTH = 64;
private static final String SOCKET_NAME = "scrcpy";
private static final String SSH_SOCKET_NAME = "/data/local/tmp/scrcpy";
private final LocalSocket videoSocket;
private final FileDescriptor videoFd;
@ -42,11 +41,11 @@ public final class DesktopConnection implements Closeable {
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 controlSocket;
if (tunnelForward) {
LocalServerSocket localServerSocket = new LocalServerSocket(sshMode ? SSH_SOCKET_NAME : SOCKET_NAME);
LocalServerSocket localServerSocket = new LocalServerSocket(SOCKET_NAME);
try {
videoSocket = localServerSocket.accept();
// 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();
}
} else {
videoSocket = connect(sshMode ? SSH_SOCKET_NAME : SOCKET_NAME);
videoSocket = connect(SOCKET_NAME);
try {
controlSocket = connect(sshMode ? SSH_SOCKET_NAME : SOCKET_NAME);
controlSocket = connect(SOCKET_NAME);
} catch (IOException | RuntimeException e) {
videoSocket.close();
throw e;

View file

@ -16,7 +16,6 @@ public class Options {
private boolean showTouches;
private boolean stayAwake;
private String codecOptions;
private boolean sshMode;
public Ln.Level getLogLevel() {
return logLevel;
@ -121,12 +120,4 @@ public class Options {
public void setCodecOptions(String codecOptions) {
this.codecOptions = codecOptions;
}
public boolean isSshMode() {
return sshMode;
}
public void setSshMode(boolean sshMode) {
this.sshMode = sshMode;
}
}

View file

@ -52,9 +52,8 @@ public final class Server {
CleanUp.configure(mustDisableShowTouchesOnCleanUp, restoreStayOn, true);
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);
if (options.getControl()) {
@ -121,7 +120,7 @@ public final class Server {
"The server version (" + BuildConfig.VERSION_NAME + ") does not match the client " + "(" + clientVersion + ")");
}
final int expectedParameters = 15;
final int expectedParameters = 14;
if (args.length != expectedParameters) {
throw new IllegalArgumentException("Expecting " + expectedParameters + " parameters");
}
@ -168,9 +167,6 @@ public final class Server {
String codecOptions = args[13];
options.setCodecOptions(codecOptions);
boolean sshMode = Boolean.parseBoolean(args[14]);
options.setSshMode(sshMode);
return options;
}