2018-02-08 22:16:27 +08:00
|
|
|
#include "server.h"
|
2018-01-22 18:22:31 +08:00
|
|
|
|
2019-11-28 04:11:40 +08:00
|
|
|
#include <assert.h>
|
2018-01-22 18:22:31 +08:00
|
|
|
#include <errno.h>
|
Replace SDL_net by custom implementation
SDL_net is not very suitable for scrcpy.
For example, SDLNet_TCP_Accept() is non-blocking, so we have to wrap it
by calling many SDL_Net-specific functions to make it blocking.
But above all, SDLNet_TCP_Open() is a server socket only when no IP is
provided; otherwise, it's a client socket. Therefore, it is not possible
to create a server socket bound to localhost, so it accepts connections
from anywhere.
This is a problem for scrcpy, because on start, the application listens
for nearly 1 second until it accepts the first connection, supposedly
from the device. If someone on the local network manages to connect to
the server socket first, then they can stream arbitrary H.264 video.
This may be troublesome, for example during a public presentation ;-)
Provide our own simplified API (net.h) instead, implemented for the
different platforms.
2018-02-16 05:59:21 +08:00
|
|
|
#include <inttypes.h>
|
2018-05-13 21:33:13 +08:00
|
|
|
#include <stdio.h>
|
2018-03-12 15:35:51 +08:00
|
|
|
#include <SDL2/SDL_timer.h>
|
2019-12-14 14:34:49 +08:00
|
|
|
#include <SDL2/SDL_platform.h>
|
2018-02-13 17:10:18 +08:00
|
|
|
|
2021-01-03 21:55:15 +08:00
|
|
|
#include "adb.h"
|
2021-11-11 23:12:17 +08:00
|
|
|
#include "util/file.h"
|
2019-11-24 18:53:00 +08:00
|
|
|
#include "util/log.h"
|
2021-11-13 01:50:50 +08:00
|
|
|
#include "util/net_intr.h"
|
|
|
|
#include "util/process_intr.h"
|
2019-12-14 14:34:49 +08:00
|
|
|
#include "util/str_util.h"
|
2018-01-22 18:22:31 +08:00
|
|
|
|
2018-01-23 22:46:34 +08:00
|
|
|
#define SOCKET_NAME "scrcpy"
|
2019-10-31 06:40:10 +08:00
|
|
|
#define SERVER_FILENAME "scrcpy-server"
|
2018-01-23 22:46:34 +08:00
|
|
|
|
2019-06-12 17:14:08 +08:00
|
|
|
#define DEFAULT_SERVER_PATH PREFIX "/share/scrcpy/" SERVER_FILENAME
|
2019-11-22 22:23:57 +08:00
|
|
|
#define DEVICE_SERVER_PATH "/data/local/tmp/scrcpy-server.jar"
|
2018-02-28 22:13:56 +08:00
|
|
|
|
2019-12-15 01:13:56 +08:00
|
|
|
static char *
|
2019-03-03 03:09:56 +08:00
|
|
|
get_server_path(void) {
|
2019-12-14 14:34:49 +08:00
|
|
|
#ifdef __WINDOWS__
|
|
|
|
const wchar_t *server_path_env = _wgetenv(L"SCRCPY_SERVER_PATH");
|
|
|
|
#else
|
2019-06-10 21:14:10 +08:00
|
|
|
const char *server_path_env = getenv("SCRCPY_SERVER_PATH");
|
2019-12-14 14:34:49 +08:00
|
|
|
#endif
|
2019-06-10 21:14:10 +08:00
|
|
|
if (server_path_env) {
|
|
|
|
// if the envvar is set, use it
|
2019-12-14 14:34:49 +08:00
|
|
|
#ifdef __WINDOWS__
|
|
|
|
char *server_path = utf8_from_wide_char(server_path_env);
|
|
|
|
#else
|
2021-01-24 22:14:53 +08:00
|
|
|
char *server_path = strdup(server_path_env);
|
2019-12-14 14:34:49 +08:00
|
|
|
#endif
|
2019-12-15 01:13:56 +08:00
|
|
|
if (!server_path) {
|
|
|
|
LOGE("Could not allocate memory");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
LOGD("Using SCRCPY_SERVER_PATH: %s", server_path);
|
|
|
|
return server_path;
|
2019-06-10 21:14:10 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
#ifndef PORTABLE
|
|
|
|
LOGD("Using server: " DEFAULT_SERVER_PATH);
|
2021-01-24 22:14:53 +08:00
|
|
|
char *server_path = strdup(DEFAULT_SERVER_PATH);
|
2019-12-15 01:13:56 +08:00
|
|
|
if (!server_path) {
|
|
|
|
LOGE("Could not allocate memory");
|
|
|
|
return NULL;
|
|
|
|
}
|
2019-06-10 21:14:10 +08:00
|
|
|
#else
|
2021-11-11 23:21:07 +08:00
|
|
|
char *server_path = sc_file_get_local_path(SERVER_FILENAME);
|
2018-02-02 16:31:44 +08:00
|
|
|
if (!server_path) {
|
2021-10-23 00:51:20 +08:00
|
|
|
LOGE("Could not get local file path, "
|
2019-06-10 21:14:10 +08:00
|
|
|
"using " SERVER_FILENAME " from current directory");
|
2021-04-23 01:59:46 +08:00
|
|
|
return strdup(SERVER_FILENAME);
|
2018-01-23 22:46:34 +08:00
|
|
|
}
|
2019-06-10 21:14:10 +08:00
|
|
|
|
|
|
|
LOGD("Using server (portable): %s", server_path);
|
|
|
|
#endif
|
2021-10-26 00:08:31 +08:00
|
|
|
|
|
|
|
return server_path;
|
2018-02-13 18:55:12 +08:00
|
|
|
}
|
|
|
|
|
2021-10-28 05:40:52 +08:00
|
|
|
static void
|
|
|
|
server_params_destroy(struct server_params *params) {
|
|
|
|
// The server stores a copy of the params provided by the user
|
|
|
|
free((char *) params->serial);
|
|
|
|
free((char *) params->crop);
|
|
|
|
free((char *) params->codec_options);
|
|
|
|
free((char *) params->encoder_name);
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
|
|
|
server_params_copy(struct server_params *dst, const struct server_params *src) {
|
|
|
|
*dst = *src;
|
|
|
|
|
|
|
|
// The params reference user-allocated memory, so we must copy them to
|
|
|
|
// handle them from another thread
|
|
|
|
|
|
|
|
#define COPY(FIELD) \
|
|
|
|
dst->FIELD = NULL; \
|
|
|
|
if (src->FIELD) { \
|
|
|
|
dst->FIELD = strdup(src->FIELD); \
|
|
|
|
if (!dst->FIELD) { \
|
|
|
|
goto error; \
|
|
|
|
} \
|
|
|
|
}
|
|
|
|
|
|
|
|
COPY(serial);
|
|
|
|
COPY(crop);
|
|
|
|
COPY(codec_options);
|
|
|
|
COPY(encoder_name);
|
|
|
|
#undef COPY
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
error:
|
|
|
|
server_params_destroy(dst);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2019-03-03 06:52:22 +08:00
|
|
|
static bool
|
2021-11-13 01:50:50 +08:00
|
|
|
push_server(struct sc_intr *intr, const char *serial) {
|
2019-12-15 01:13:56 +08:00
|
|
|
char *server_path = get_server_path();
|
|
|
|
if (!server_path) {
|
|
|
|
return false;
|
|
|
|
}
|
2021-11-11 23:21:07 +08:00
|
|
|
if (!sc_file_is_regular(server_path)) {
|
2019-12-06 04:07:11 +08:00
|
|
|
LOGE("'%s' does not exist or is not a regular file\n", server_path);
|
2021-01-24 22:14:53 +08:00
|
|
|
free(server_path);
|
2019-12-06 04:07:11 +08:00
|
|
|
return false;
|
|
|
|
}
|
2021-11-12 00:48:41 +08:00
|
|
|
sc_pid pid = adb_push(serial, server_path, DEVICE_SERVER_PATH);
|
2021-01-24 22:14:53 +08:00
|
|
|
free(server_path);
|
2021-11-13 01:50:50 +08:00
|
|
|
return sc_process_check_success_intr(intr, pid, "adb push");
|
2018-01-23 22:46:34 +08:00
|
|
|
}
|
|
|
|
|
2019-03-03 06:52:22 +08:00
|
|
|
static bool
|
2021-11-13 01:50:50 +08:00
|
|
|
enable_tunnel_reverse(struct sc_intr *intr, const char *serial,
|
|
|
|
uint16_t local_port) {
|
2021-11-12 00:48:41 +08:00
|
|
|
sc_pid pid = adb_reverse(serial, SOCKET_NAME, local_port);
|
2021-11-13 01:50:50 +08:00
|
|
|
return sc_process_check_success_intr(intr, pid, "adb reverse");
|
2018-01-23 22:46:34 +08:00
|
|
|
}
|
|
|
|
|
2019-03-03 06:52:22 +08:00
|
|
|
static bool
|
2021-11-13 01:50:50 +08:00
|
|
|
disable_tunnel_reverse(struct sc_intr *intr, const char *serial) {
|
2021-11-12 00:48:41 +08:00
|
|
|
sc_pid pid = adb_reverse_remove(serial, SOCKET_NAME);
|
2021-11-13 01:50:50 +08:00
|
|
|
return sc_process_check_success_intr(intr, pid, "adb reverse --remove");
|
2018-01-23 22:46:34 +08:00
|
|
|
}
|
|
|
|
|
2019-03-03 06:52:22 +08:00
|
|
|
static bool
|
2021-11-13 01:50:50 +08:00
|
|
|
enable_tunnel_forward(struct sc_intr *intr, const char *serial,
|
|
|
|
uint16_t local_port) {
|
2021-11-12 00:48:41 +08:00
|
|
|
sc_pid pid = adb_forward(serial, local_port, SOCKET_NAME);
|
2021-11-13 01:50:50 +08:00
|
|
|
return sc_process_check_success_intr(intr, pid, "adb forward");
|
2018-03-12 15:35:51 +08:00
|
|
|
}
|
|
|
|
|
2019-03-03 06:52:22 +08:00
|
|
|
static bool
|
2021-11-13 01:50:50 +08:00
|
|
|
disable_tunnel_forward(struct sc_intr *intr, const char *serial,
|
|
|
|
uint16_t local_port) {
|
2021-11-12 00:48:41 +08:00
|
|
|
sc_pid pid = adb_forward_remove(serial, local_port);
|
2021-11-13 01:50:50 +08:00
|
|
|
return sc_process_check_success_intr(intr, pid, "adb forward --remove");
|
2018-03-12 15:35:51 +08:00
|
|
|
}
|
|
|
|
|
2019-12-10 05:14:43 +08:00
|
|
|
static bool
|
|
|
|
disable_tunnel(struct server *server) {
|
2021-11-01 18:08:01 +08:00
|
|
|
assert(server->tunnel_enabled);
|
|
|
|
|
2021-10-28 05:40:52 +08:00
|
|
|
const char *serial = server->params.serial;
|
2021-11-01 18:08:01 +08:00
|
|
|
bool ok = server->tunnel_forward
|
2021-11-13 01:50:50 +08:00
|
|
|
? disable_tunnel_forward(&server->intr, serial, server->local_port)
|
|
|
|
: disable_tunnel_reverse(&server->intr, serial);
|
2021-11-01 18:08:01 +08:00
|
|
|
|
|
|
|
// Consider tunnel disabled even if the command failed
|
|
|
|
server->tunnel_enabled = false;
|
|
|
|
|
|
|
|
return ok;
|
2019-12-10 05:14:43 +08:00
|
|
|
}
|
|
|
|
|
2021-11-01 05:01:57 +08:00
|
|
|
static bool
|
2021-11-13 01:50:50 +08:00
|
|
|
listen_on_port(struct sc_intr *intr, sc_socket socket, uint16_t port) {
|
|
|
|
return net_listen_intr(intr, socket, IPV4_LOCALHOST, port, 1);
|
2019-12-10 05:14:43 +08:00
|
|
|
}
|
|
|
|
|
2019-03-03 06:52:22 +08:00
|
|
|
static bool
|
2019-12-10 04:16:09 +08:00
|
|
|
enable_tunnel_reverse_any_port(struct server *server,
|
2020-06-20 04:04:06 +08:00
|
|
|
struct sc_port_range port_range) {
|
2021-10-28 05:40:52 +08:00
|
|
|
const char *serial = server->params.serial;
|
2019-12-10 04:16:09 +08:00
|
|
|
uint16_t port = port_range.first;
|
|
|
|
for (;;) {
|
2021-11-13 01:50:50 +08:00
|
|
|
if (!enable_tunnel_reverse(&server->intr, serial, port)) {
|
2019-12-10 04:16:09 +08:00
|
|
|
// the command itself failed, it will fail on any port
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2019-12-10 05:10:42 +08:00
|
|
|
// At the application level, the device part is "the server" because it
|
|
|
|
// serves video stream and control. However, at the network level, the
|
|
|
|
// client listens and the server connects to the client. That way, the
|
|
|
|
// client can listen before starting the server app, so there is no
|
|
|
|
// need to try to connect until the server socket is listening on the
|
|
|
|
// device.
|
2021-11-01 05:01:57 +08:00
|
|
|
sc_socket server_socket = net_socket();
|
2021-11-01 18:44:58 +08:00
|
|
|
if (server_socket != SC_INVALID_SOCKET) {
|
2021-11-13 01:50:50 +08:00
|
|
|
bool ok = listen_on_port(&server->intr, server_socket, port);
|
2021-11-01 05:01:57 +08:00
|
|
|
if (ok) {
|
|
|
|
// success
|
|
|
|
server->server_socket = server_socket;
|
|
|
|
server->local_port = port;
|
|
|
|
server->tunnel_enabled = true;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
net_close(server_socket);
|
2019-12-10 04:16:09 +08:00
|
|
|
}
|
|
|
|
|
2021-11-13 01:50:50 +08:00
|
|
|
if (sc_intr_is_interrupted(&server->intr)) {
|
|
|
|
// Stop immediately
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2019-12-10 04:16:09 +08:00
|
|
|
// failure, disable tunnel and try another port
|
2021-11-13 01:50:50 +08:00
|
|
|
if (!disable_tunnel_reverse(&server->intr, serial)) {
|
2019-12-10 04:16:09 +08:00
|
|
|
LOGW("Could not remove reverse tunnel on port %" PRIu16, port);
|
|
|
|
}
|
|
|
|
|
|
|
|
// check before incrementing to avoid overflow on port 65535
|
|
|
|
if (port < port_range.last) {
|
|
|
|
LOGW("Could not listen on port %" PRIu16", retrying on %" PRIu16,
|
2020-04-13 22:22:43 +08:00
|
|
|
port, (uint16_t) (port + 1));
|
2019-12-10 04:16:09 +08:00
|
|
|
port++;
|
|
|
|
continue;
|
2019-12-10 05:10:42 +08:00
|
|
|
}
|
|
|
|
|
2019-12-10 04:16:09 +08:00
|
|
|
if (port_range.first == port_range.last) {
|
|
|
|
LOGE("Could not listen on port %" PRIu16, port_range.first);
|
|
|
|
} else {
|
|
|
|
LOGE("Could not listen on any port in range %" PRIu16 ":%" PRIu16,
|
|
|
|
port_range.first, port_range.last);
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
|
|
|
enable_tunnel_forward_any_port(struct server *server,
|
2020-06-20 04:04:06 +08:00
|
|
|
struct sc_port_range port_range) {
|
2019-12-10 04:16:09 +08:00
|
|
|
server->tunnel_forward = true;
|
2021-10-28 05:40:52 +08:00
|
|
|
|
|
|
|
const char *serial = server->params.serial;
|
2019-12-10 04:16:09 +08:00
|
|
|
uint16_t port = port_range.first;
|
|
|
|
for (;;) {
|
2021-11-13 01:50:50 +08:00
|
|
|
if (enable_tunnel_forward(&server->intr, serial, port)) {
|
2019-12-10 04:16:09 +08:00
|
|
|
// success
|
|
|
|
server->local_port = port;
|
2021-11-01 18:08:01 +08:00
|
|
|
server->tunnel_enabled = true;
|
2019-12-10 04:16:09 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2021-11-13 01:50:50 +08:00
|
|
|
if (sc_intr_is_interrupted(&server->intr)) {
|
|
|
|
// Stop immediately
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2019-12-10 04:16:09 +08:00
|
|
|
if (port < port_range.last) {
|
|
|
|
LOGW("Could not forward port %" PRIu16", retrying on %" PRIu16,
|
2020-08-31 19:37:09 +08:00
|
|
|
port, (uint16_t) (port + 1));
|
2019-12-10 04:16:09 +08:00
|
|
|
port++;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (port_range.first == port_range.last) {
|
|
|
|
LOGE("Could not forward port %" PRIu16, port_range.first);
|
|
|
|
} else {
|
|
|
|
LOGE("Could not forward any port in range %" PRIu16 ":%" PRIu16,
|
|
|
|
port_range.first, port_range.last);
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
2020-06-20 04:04:06 +08:00
|
|
|
enable_tunnel_any_port(struct server *server, struct sc_port_range port_range,
|
2020-05-25 05:27:34 +08:00
|
|
|
bool force_adb_forward) {
|
|
|
|
if (!force_adb_forward) {
|
|
|
|
// Attempt to use "adb reverse"
|
|
|
|
if (enable_tunnel_reverse_any_port(server, port_range)) {
|
|
|
|
return true;
|
|
|
|
}
|
2018-03-12 15:35:51 +08:00
|
|
|
|
2020-05-25 05:27:34 +08:00
|
|
|
// if "adb reverse" does not work (e.g. over "adb connect"), it
|
|
|
|
// fallbacks to "adb forward", so the app socket is the client
|
|
|
|
|
|
|
|
LOGW("'adb reverse' failed, fallback to 'adb forward'");
|
|
|
|
}
|
2019-12-10 04:16:09 +08:00
|
|
|
|
|
|
|
return enable_tunnel_forward_any_port(server, port_range);
|
2018-03-12 15:35:51 +08:00
|
|
|
}
|
|
|
|
|
2020-05-25 03:51:40 +08:00
|
|
|
static const char *
|
|
|
|
log_level_to_server_string(enum sc_log_level level) {
|
|
|
|
switch (level) {
|
2021-06-18 03:40:30 +08:00
|
|
|
case SC_LOG_LEVEL_VERBOSE:
|
|
|
|
return "verbose";
|
2020-05-25 03:51:40 +08:00
|
|
|
case SC_LOG_LEVEL_DEBUG:
|
|
|
|
return "debug";
|
|
|
|
case SC_LOG_LEVEL_INFO:
|
|
|
|
return "info";
|
|
|
|
case SC_LOG_LEVEL_WARN:
|
|
|
|
return "warn";
|
|
|
|
case SC_LOG_LEVEL_ERROR:
|
|
|
|
return "error";
|
|
|
|
default:
|
|
|
|
assert(!"unexpected log level");
|
|
|
|
return "(unknown)";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-11-12 00:48:41 +08:00
|
|
|
static sc_pid
|
2019-06-05 05:59:55 +08:00
|
|
|
execute_server(struct server *server, const struct server_params *params) {
|
2021-10-28 05:40:52 +08:00
|
|
|
const char *serial = server->params.serial;
|
|
|
|
|
2018-02-01 19:18:06 +08:00
|
|
|
char max_size_string[6];
|
2018-02-01 23:36:50 +08:00
|
|
|
char bit_rate_string[11];
|
2019-11-18 05:07:19 +08:00
|
|
|
char max_fps_string[6];
|
2020-05-25 03:11:21 +08:00
|
|
|
char lock_video_orientation_string[5];
|
2021-01-04 15:16:32 +08:00
|
|
|
char display_id_string[11];
|
2019-06-05 05:59:55 +08:00
|
|
|
sprintf(max_size_string, "%"PRIu16, params->max_size);
|
|
|
|
sprintf(bit_rate_string, "%"PRIu32, params->bit_rate);
|
2019-11-18 05:07:19 +08:00
|
|
|
sprintf(max_fps_string, "%"PRIu16, params->max_fps);
|
2021-07-16 00:07:39 +08:00
|
|
|
sprintf(lock_video_orientation_string, "%"PRIi8,
|
|
|
|
params->lock_video_orientation);
|
2021-01-04 15:16:32 +08:00
|
|
|
sprintf(display_id_string, "%"PRIu32, params->display_id);
|
2018-01-22 18:22:31 +08:00
|
|
|
const char *const cmd[] = {
|
|
|
|
"shell",
|
2019-11-22 22:16:00 +08:00
|
|
|
"CLASSPATH=" DEVICE_SERVER_PATH,
|
2018-01-22 18:22:31 +08:00
|
|
|
"app_process",
|
2019-11-04 02:31:56 +08:00
|
|
|
#ifdef SERVER_DEBUGGER
|
|
|
|
# define SERVER_DEBUGGER_PORT "5005"
|
2020-03-20 02:15:43 +08:00
|
|
|
# ifdef SERVER_DEBUGGER_METHOD_NEW
|
|
|
|
/* Android 9 and above */
|
2021-07-16 00:07:39 +08:00
|
|
|
"-XjdwpProvider:internal -XjdwpOptions:transport=dt_socket,suspend=y,"
|
|
|
|
"server=y,address="
|
2020-03-20 02:15:43 +08:00
|
|
|
# else
|
|
|
|
/* Android 8 and below */
|
2019-11-04 02:31:56 +08:00
|
|
|
"-agentlib:jdwp=transport=dt_socket,suspend=y,server=y,address="
|
2020-03-20 02:15:43 +08:00
|
|
|
# endif
|
2019-11-04 02:31:56 +08:00
|
|
|
SERVER_DEBUGGER_PORT,
|
|
|
|
#endif
|
2018-01-30 00:06:44 +08:00
|
|
|
"/", // unused
|
2018-02-28 21:57:18 +08:00
|
|
|
"com.genymobile.scrcpy.Server",
|
2019-11-10 20:23:58 +08:00
|
|
|
SCRCPY_VERSION,
|
2020-05-25 03:51:40 +08:00
|
|
|
log_level_to_server_string(params->log_level),
|
2018-02-01 19:18:06 +08:00
|
|
|
max_size_string,
|
2018-02-01 23:36:50 +08:00
|
|
|
bit_rate_string,
|
2019-11-18 05:07:19 +08:00
|
|
|
max_fps_string,
|
2020-02-16 19:30:36 +08:00
|
|
|
lock_video_orientation_string,
|
2019-06-05 05:59:55 +08:00
|
|
|
server->tunnel_forward ? "true" : "false",
|
|
|
|
params->crop ? params->crop : "-",
|
2019-07-31 07:55:32 +08:00
|
|
|
"true", // always send frame meta (packet boundaries + timestamp)
|
2019-06-05 03:31:46 +08:00
|
|
|
params->control ? "true" : "false",
|
2020-02-24 19:16:38 +08:00
|
|
|
display_id_string,
|
2020-05-02 05:49:37 +08:00
|
|
|
params->show_touches ? "true" : "false",
|
2020-05-02 07:54:48 +08:00
|
|
|
params->stay_awake ? "true" : "false",
|
2020-04-26 20:22:08 +08:00
|
|
|
params->codec_options ? params->codec_options : "-",
|
2020-10-12 17:23:06 +08:00
|
|
|
params->encoder_name ? params->encoder_name : "-",
|
2021-02-21 08:42:04 +08:00
|
|
|
params->power_off_on_close ? "true" : "false",
|
2018-01-22 18:22:31 +08:00
|
|
|
};
|
2019-11-04 02:31:56 +08:00
|
|
|
#ifdef SERVER_DEBUGGER
|
|
|
|
LOGI("Server debugger waiting for a client on device port "
|
|
|
|
SERVER_DEBUGGER_PORT "...");
|
|
|
|
// From the computer, run
|
|
|
|
// adb forward tcp:5005 tcp:5005
|
|
|
|
// Then, from Android Studio: Run > Debug > Edit configurations...
|
|
|
|
// On the left, click on '+', "Remote", with:
|
|
|
|
// Host: localhost
|
|
|
|
// Port: 5005
|
|
|
|
// Then click on "Debug"
|
|
|
|
#endif
|
2021-10-28 05:40:52 +08:00
|
|
|
return adb_execute(serial, cmd, ARRAY_LEN(cmd));
|
2018-01-22 18:22:31 +08:00
|
|
|
}
|
|
|
|
|
2021-11-01 05:01:57 +08:00
|
|
|
static bool
|
2021-11-13 01:50:50 +08:00
|
|
|
connect_and_read_byte(struct sc_intr *intr, sc_socket socket, uint16_t port) {
|
|
|
|
bool ok = net_connect_intr(intr, socket, IPV4_LOCALHOST, port);
|
2021-11-01 05:01:57 +08:00
|
|
|
if (!ok) {
|
|
|
|
return false;
|
2018-03-12 15:35:51 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
char byte;
|
|
|
|
// the connection may succeed even if the server behind the "adb tunnel"
|
|
|
|
// is not listening, so read one byte to detect a working connection
|
2021-11-13 01:50:50 +08:00
|
|
|
if (net_recv_intr(intr, socket, &byte, 1) != 1) {
|
2018-03-12 15:35:51 +08:00
|
|
|
// the server is not listening yet behind the adb tunnel
|
2021-11-01 05:01:57 +08:00
|
|
|
return false;
|
2018-03-12 15:35:51 +08:00
|
|
|
}
|
2021-11-01 05:01:57 +08:00
|
|
|
|
|
|
|
return true;
|
2018-03-12 15:35:51 +08:00
|
|
|
}
|
|
|
|
|
2021-10-27 04:49:45 +08:00
|
|
|
static sc_socket
|
2021-10-31 21:56:37 +08:00
|
|
|
connect_to_server(struct server *server, uint32_t attempts, sc_tick delay) {
|
|
|
|
uint16_t port = server->local_port;
|
2018-03-12 15:35:51 +08:00
|
|
|
do {
|
|
|
|
LOGD("Remaining connection attempts: %d", (int) attempts);
|
2021-11-01 05:01:57 +08:00
|
|
|
sc_socket socket = net_socket();
|
2021-10-27 04:49:45 +08:00
|
|
|
if (socket != SC_INVALID_SOCKET) {
|
2021-11-13 01:50:50 +08:00
|
|
|
bool ok = connect_and_read_byte(&server->intr, socket, port);
|
2021-11-01 05:01:57 +08:00
|
|
|
if (ok) {
|
|
|
|
// it worked!
|
|
|
|
return socket;
|
|
|
|
}
|
|
|
|
|
|
|
|
net_close(socket);
|
2018-03-12 15:35:51 +08:00
|
|
|
}
|
|
|
|
if (attempts) {
|
2021-10-31 21:56:37 +08:00
|
|
|
sc_mutex_lock(&server->mutex);
|
|
|
|
sc_tick deadline = sc_tick_now() + delay;
|
|
|
|
bool timed_out = false;
|
|
|
|
while (!server->stopped && !timed_out) {
|
|
|
|
timed_out = !sc_cond_timedwait(&server->cond_stopped,
|
|
|
|
&server->mutex, deadline);
|
|
|
|
}
|
|
|
|
bool stopped = server->stopped;
|
|
|
|
sc_mutex_unlock(&server->mutex);
|
|
|
|
|
|
|
|
if (stopped) {
|
|
|
|
LOGI("Connection attempt stopped");
|
|
|
|
break;
|
|
|
|
}
|
2018-03-12 15:35:51 +08:00
|
|
|
}
|
|
|
|
} while (--attempts > 0);
|
2021-10-27 04:49:45 +08:00
|
|
|
return SC_INVALID_SOCKET;
|
2018-03-12 15:35:51 +08:00
|
|
|
}
|
|
|
|
|
2021-01-01 23:34:47 +08:00
|
|
|
bool
|
2021-10-30 21:33:23 +08:00
|
|
|
server_init(struct server *server, const struct server_params *params,
|
|
|
|
const struct server_callbacks *cbs, void *cbs_userdata) {
|
2021-10-28 05:40:52 +08:00
|
|
|
bool ok = server_params_copy(&server->params, params);
|
|
|
|
if (!ok) {
|
|
|
|
LOGE("Could not copy server params");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2021-10-31 21:56:37 +08:00
|
|
|
ok = sc_mutex_init(&server->mutex);
|
|
|
|
if (!ok) {
|
|
|
|
LOGE("Could not create server mutex");
|
|
|
|
server_params_destroy(&server->params);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
ok = sc_cond_init(&server->cond_stopped);
|
|
|
|
if (!ok) {
|
|
|
|
LOGE("Could not create server cond_stopped");
|
|
|
|
sc_mutex_destroy(&server->mutex);
|
|
|
|
server_params_destroy(&server->params);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2021-11-13 01:50:50 +08:00
|
|
|
ok = sc_intr_init(&server->intr);
|
|
|
|
if (!ok) {
|
|
|
|
LOGE("Could not create intr");
|
|
|
|
sc_cond_destroy(&server->cond_stopped);
|
|
|
|
sc_mutex_destroy(&server->mutex);
|
|
|
|
server_params_destroy(&server->params);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2021-10-31 21:56:37 +08:00
|
|
|
server->stopped = false;
|
2021-01-01 23:34:47 +08:00
|
|
|
|
2021-10-27 04:49:45 +08:00
|
|
|
server->server_socket = SC_INVALID_SOCKET;
|
|
|
|
server->video_socket = SC_INVALID_SOCKET;
|
|
|
|
server->control_socket = SC_INVALID_SOCKET;
|
2021-01-01 23:34:47 +08:00
|
|
|
|
|
|
|
server->local_port = 0;
|
|
|
|
|
|
|
|
server->tunnel_enabled = false;
|
|
|
|
server->tunnel_forward = false;
|
|
|
|
|
2021-10-30 21:33:23 +08:00
|
|
|
assert(cbs);
|
|
|
|
assert(cbs->on_connection_failed);
|
|
|
|
assert(cbs->on_connected);
|
|
|
|
assert(cbs->on_disconnected);
|
|
|
|
|
|
|
|
server->cbs = cbs;
|
|
|
|
server->cbs_userdata = cbs_userdata;
|
|
|
|
|
2021-01-01 23:34:47 +08:00
|
|
|
return true;
|
2018-02-08 22:16:27 +08:00
|
|
|
}
|
|
|
|
|
2021-05-09 22:52:22 +08:00
|
|
|
static bool
|
2021-11-13 01:50:50 +08:00
|
|
|
device_read_info(struct sc_intr *intr, sc_socket device_socket,
|
|
|
|
struct server_info *info) {
|
2021-05-09 22:52:22 +08:00
|
|
|
unsigned char buf[DEVICE_NAME_FIELD_LENGTH + 4];
|
2021-11-13 01:50:50 +08:00
|
|
|
ssize_t r = net_recv_all_intr(intr, device_socket, buf, sizeof(buf));
|
2021-05-09 22:52:22 +08:00
|
|
|
if (r < DEVICE_NAME_FIELD_LENGTH + 4) {
|
|
|
|
LOGE("Could not retrieve device information");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
// in case the client sends garbage
|
|
|
|
buf[DEVICE_NAME_FIELD_LENGTH - 1] = '\0';
|
2021-10-31 01:07:35 +08:00
|
|
|
memcpy(info->device_name, (char *) buf, sizeof(info->device_name));
|
|
|
|
|
|
|
|
info->frame_size.width = (buf[DEVICE_NAME_FIELD_LENGTH] << 8)
|
|
|
|
| buf[DEVICE_NAME_FIELD_LENGTH + 1];
|
|
|
|
info->frame_size.height = (buf[DEVICE_NAME_FIELD_LENGTH + 2] << 8)
|
|
|
|
| buf[DEVICE_NAME_FIELD_LENGTH + 3];
|
2021-05-09 22:52:22 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2021-10-30 21:33:23 +08:00
|
|
|
static bool
|
2021-10-31 01:07:35 +08:00
|
|
|
server_connect_to(struct server *server, struct server_info *info) {
|
2021-11-01 18:44:58 +08:00
|
|
|
assert(server->tunnel_enabled);
|
|
|
|
|
|
|
|
sc_socket video_socket = SC_INVALID_SOCKET;
|
|
|
|
sc_socket control_socket = SC_INVALID_SOCKET;
|
2018-03-12 15:35:51 +08:00
|
|
|
if (!server->tunnel_forward) {
|
2021-11-13 01:50:50 +08:00
|
|
|
video_socket = net_accept_intr(&server->intr, server->server_socket);
|
2021-11-01 18:44:58 +08:00
|
|
|
if (video_socket == SC_INVALID_SOCKET) {
|
|
|
|
goto fail;
|
2019-05-29 03:03:54 +08:00
|
|
|
}
|
|
|
|
|
2021-11-13 01:50:50 +08:00
|
|
|
control_socket = net_accept_intr(&server->intr, server->server_socket);
|
2021-11-01 18:44:58 +08:00
|
|
|
if (control_socket == SC_INVALID_SOCKET) {
|
|
|
|
goto fail;
|
2019-05-29 03:02:57 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// we don't need the server socket anymore
|
2021-10-27 04:49:45 +08:00
|
|
|
if (!net_close(server->server_socket)) {
|
|
|
|
LOGW("Could not close server socket on connect");
|
2020-03-29 06:56:25 +08:00
|
|
|
}
|
2021-11-13 04:40:22 +08:00
|
|
|
|
|
|
|
// server_socket is never used anymore
|
2018-03-12 15:35:51 +08:00
|
|
|
} else {
|
2019-03-03 06:52:22 +08:00
|
|
|
uint32_t attempts = 100;
|
2021-10-31 21:56:37 +08:00
|
|
|
sc_tick delay = SC_TICK_FROM_MS(100);
|
|
|
|
video_socket = connect_to_server(server, attempts, delay);
|
2021-11-01 18:44:58 +08:00
|
|
|
if (video_socket == SC_INVALID_SOCKET) {
|
|
|
|
goto fail;
|
2019-05-29 03:03:54 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// we know that the device is listening, we don't need several attempts
|
2021-11-01 05:01:57 +08:00
|
|
|
control_socket = net_socket();
|
2021-11-01 18:44:58 +08:00
|
|
|
if (control_socket == SC_INVALID_SOCKET) {
|
|
|
|
goto fail;
|
2019-05-29 03:02:57 +08:00
|
|
|
}
|
2021-11-13 01:50:50 +08:00
|
|
|
bool ok = net_connect_intr(&server->intr, control_socket,
|
|
|
|
IPV4_LOCALHOST, server->local_port);
|
2021-11-01 05:01:57 +08:00
|
|
|
if (!ok) {
|
|
|
|
goto fail;
|
|
|
|
}
|
2018-03-12 15:35:51 +08:00
|
|
|
}
|
2018-02-09 00:38:38 +08:00
|
|
|
|
|
|
|
// we don't need the adb tunnel anymore
|
2018-03-12 15:35:51 +08:00
|
|
|
disable_tunnel(server); // ignore failure
|
2018-02-09 00:38:38 +08:00
|
|
|
|
2021-05-09 22:52:22 +08:00
|
|
|
// The sockets will be closed on stop if device_read_info() fails
|
2021-11-13 01:50:50 +08:00
|
|
|
bool ok = device_read_info(&server->intr, video_socket, info);
|
2021-11-01 18:44:58 +08:00
|
|
|
if (!ok) {
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
|
|
|
|
assert(video_socket != SC_INVALID_SOCKET);
|
|
|
|
assert(control_socket != SC_INVALID_SOCKET);
|
|
|
|
|
|
|
|
server->video_socket = video_socket;
|
|
|
|
server->control_socket = control_socket;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
fail:
|
|
|
|
if (video_socket != SC_INVALID_SOCKET) {
|
|
|
|
if (!net_close(video_socket)) {
|
|
|
|
LOGW("Could not close video socket");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (control_socket != SC_INVALID_SOCKET) {
|
|
|
|
if (!net_close(control_socket)) {
|
|
|
|
LOGW("Could not close control socket");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-10-30 21:33:23 +08:00
|
|
|
// Always leave this function with tunnel disabled
|
|
|
|
disable_tunnel(server);
|
|
|
|
|
2021-11-01 18:44:58 +08:00
|
|
|
return false;
|
2018-02-08 22:16:27 +08:00
|
|
|
}
|
|
|
|
|
2021-11-13 01:30:20 +08:00
|
|
|
static void
|
|
|
|
server_on_terminated(void *userdata) {
|
|
|
|
struct server *server = userdata;
|
|
|
|
|
2021-11-13 04:40:22 +08:00
|
|
|
// If the server process dies before connecting to the server socket,
|
|
|
|
// then the client will be stuck forever on accept(). To avoid the problem,
|
|
|
|
// wake up the accept() call (or any other) when the server dies, like on
|
|
|
|
// stop() (it is safe to call interrupt() twice).
|
|
|
|
sc_intr_interrupt(&server->intr);
|
2021-11-13 01:30:20 +08:00
|
|
|
|
2021-10-30 21:33:23 +08:00
|
|
|
server->cbs->on_disconnected(server, server->cbs_userdata);
|
|
|
|
|
2021-11-13 01:30:20 +08:00
|
|
|
LOGD("Server terminated");
|
|
|
|
}
|
|
|
|
|
2021-10-30 21:33:23 +08:00
|
|
|
static int
|
|
|
|
run_server(void *data) {
|
|
|
|
struct server *server = data;
|
|
|
|
|
2021-11-13 01:30:20 +08:00
|
|
|
const struct server_params *params = &server->params;
|
|
|
|
|
2021-11-13 01:50:50 +08:00
|
|
|
bool ok = push_server(&server->intr, params->serial);
|
2021-10-30 21:33:23 +08:00
|
|
|
if (!ok) {
|
|
|
|
goto error_connection_failed;
|
2021-11-13 01:30:20 +08:00
|
|
|
}
|
|
|
|
|
2021-10-30 21:33:23 +08:00
|
|
|
ok = enable_tunnel_any_port(server, params->port_range,
|
|
|
|
params->force_adb_forward);
|
|
|
|
if (!ok) {
|
|
|
|
goto error_connection_failed;
|
2021-11-13 01:30:20 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// server will connect to our server socket
|
2021-10-30 21:33:23 +08:00
|
|
|
sc_pid pid = execute_server(server, params);
|
|
|
|
if (pid == SC_PROCESS_NONE) {
|
|
|
|
disable_tunnel(server);
|
|
|
|
goto error_connection_failed;
|
2021-11-13 01:30:20 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static const struct sc_process_listener listener = {
|
|
|
|
.on_terminated = server_on_terminated,
|
|
|
|
};
|
2021-10-30 21:33:23 +08:00
|
|
|
struct sc_process_observer observer;
|
|
|
|
ok = sc_process_observer_init(&observer, pid, &listener, server);
|
2021-11-13 01:30:20 +08:00
|
|
|
if (!ok) {
|
2021-10-30 21:33:23 +08:00
|
|
|
sc_process_terminate(pid);
|
|
|
|
sc_process_wait(pid, true); // ignore exit code
|
|
|
|
disable_tunnel(server);
|
|
|
|
goto error_connection_failed;
|
2021-11-13 01:30:20 +08:00
|
|
|
}
|
|
|
|
|
2021-10-30 21:33:23 +08:00
|
|
|
ok = server_connect_to(server, &server->info);
|
|
|
|
// The tunnel is always closed by server_connect_to()
|
|
|
|
if (!ok) {
|
|
|
|
sc_process_terminate(pid);
|
|
|
|
sc_process_wait(pid, true); // ignore exit code
|
|
|
|
sc_process_observer_join(&observer);
|
|
|
|
sc_process_observer_destroy(&observer);
|
|
|
|
goto error_connection_failed;
|
|
|
|
}
|
2021-11-13 01:30:20 +08:00
|
|
|
|
2021-10-30 21:33:23 +08:00
|
|
|
// Now connected
|
|
|
|
server->cbs->on_connected(server, server->cbs_userdata);
|
2021-11-13 01:30:20 +08:00
|
|
|
|
2021-10-30 21:33:23 +08:00
|
|
|
// Wait for server_stop()
|
2021-10-31 21:56:37 +08:00
|
|
|
sc_mutex_lock(&server->mutex);
|
2021-10-30 21:33:23 +08:00
|
|
|
while (!server->stopped) {
|
|
|
|
sc_cond_wait(&server->cond_stopped, &server->mutex);
|
|
|
|
}
|
2021-10-31 21:56:37 +08:00
|
|
|
sc_mutex_unlock(&server->mutex);
|
|
|
|
|
2021-01-01 19:41:25 +08:00
|
|
|
// Give some delay for the server to terminate properly
|
2021-07-04 22:50:19 +08:00
|
|
|
#define WATCHDOG_DELAY SC_TICK_FROM_SEC(1)
|
2021-11-12 16:49:37 +08:00
|
|
|
sc_tick deadline = sc_tick_now() + WATCHDOG_DELAY;
|
2021-10-30 21:33:23 +08:00
|
|
|
bool terminated = sc_process_observer_timedwait(&observer, deadline);
|
2021-01-01 19:41:25 +08:00
|
|
|
|
|
|
|
// After this delay, kill the server if it's not dead already.
|
|
|
|
// On some devices, closing the sockets is not sufficient to wake up the
|
|
|
|
// blocking calls while the device is asleep.
|
2021-11-12 16:49:37 +08:00
|
|
|
if (!terminated) {
|
|
|
|
// The process may have terminated since the check, but it is not
|
|
|
|
// reaped (closed) yet, so its PID is still valid, and it is ok to call
|
|
|
|
// sc_process_terminate() even in that case.
|
2021-01-01 19:41:25 +08:00
|
|
|
LOGW("Killing the server...");
|
2021-10-30 21:33:23 +08:00
|
|
|
sc_process_terminate(pid);
|
2021-01-01 19:41:25 +08:00
|
|
|
}
|
|
|
|
|
2021-10-30 21:33:23 +08:00
|
|
|
sc_process_observer_join(&observer);
|
|
|
|
sc_process_observer_destroy(&observer);
|
|
|
|
|
|
|
|
sc_process_close(pid);
|
|
|
|
|
|
|
|
return 0;
|
2021-11-12 16:49:37 +08:00
|
|
|
|
2021-10-30 21:33:23 +08:00
|
|
|
error_connection_failed:
|
|
|
|
server->cbs->on_connection_failed(server, server->cbs_userdata);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
server_start(struct server *server) {
|
|
|
|
bool ok = sc_thread_create(&server->thread, run_server, "server", server);
|
|
|
|
if (!ok) {
|
|
|
|
LOGE("Could not create server thread");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
server_stop(struct server *server) {
|
|
|
|
sc_mutex_lock(&server->mutex);
|
|
|
|
server->stopped = true;
|
|
|
|
sc_cond_signal(&server->cond_stopped);
|
2021-11-13 01:50:50 +08:00
|
|
|
sc_intr_interrupt(&server->intr);
|
2021-10-30 21:33:23 +08:00
|
|
|
sc_mutex_unlock(&server->mutex);
|
|
|
|
|
|
|
|
sc_thread_join(&server->thread, NULL);
|
2018-02-08 22:16:27 +08:00
|
|
|
}
|
2018-02-09 19:59:36 +08:00
|
|
|
|
2019-03-03 03:09:56 +08:00
|
|
|
void
|
|
|
|
server_destroy(struct server *server) {
|
2021-10-28 05:40:52 +08:00
|
|
|
server_params_destroy(&server->params);
|
2021-11-13 01:50:50 +08:00
|
|
|
sc_intr_destroy(&server->intr);
|
2021-10-31 21:56:37 +08:00
|
|
|
sc_cond_destroy(&server->cond_stopped);
|
|
|
|
sc_mutex_destroy(&server->mutex);
|
2018-02-09 19:59:36 +08:00
|
|
|
}
|