diff --git a/app/src/command.c b/app/src/command.c index b702dd4d..07cf9e65 100644 --- a/app/src/command.c +++ b/app/src/command.c @@ -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); diff --git a/app/src/command.h b/app/src/command.h index f196f304..bdb297a1 100644 --- a/app/src/command.h +++ b/app/src/command.h @@ -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); diff --git a/app/src/server.c b/app/src/server.c index 67495b8b..f16eb5a4 100644 --- a/app/src/server.c +++ b/app/src/server.c @@ -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); } diff --git a/app/src/server.h b/app/src/server.h index 4697300c..43ed02a7 100644 --- a/app/src/server.h +++ b/app/src/server.h @@ -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 { diff --git a/server/src/main/java/com/genymobile/scrcpy/DesktopConnection.java b/server/src/main/java/com/genymobile/scrcpy/DesktopConnection.java index 1c4538f7..0ec43040 100644 --- a/server/src/main/java/com/genymobile/scrcpy/DesktopConnection.java +++ b/server/src/main/java/com/genymobile/scrcpy/DesktopConnection.java @@ -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; diff --git a/server/src/main/java/com/genymobile/scrcpy/Options.java b/server/src/main/java/com/genymobile/scrcpy/Options.java index e9bbfe5d..06312a37 100644 --- a/server/src/main/java/com/genymobile/scrcpy/Options.java +++ b/server/src/main/java/com/genymobile/scrcpy/Options.java @@ -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; - } } diff --git a/server/src/main/java/com/genymobile/scrcpy/Server.java b/server/src/main/java/com/genymobile/scrcpy/Server.java index baf32cad..d257e319 100644 --- a/server/src/main/java/com/genymobile/scrcpy/Server.java +++ b/server/src/main/java/com/genymobile/scrcpy/Server.java @@ -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; }