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
|
|
|
|
2022-02-04 05:46:24 +08:00
|
|
|
#include "adb/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"
|
2021-11-13 06:12:51 +08:00
|
|
|
#include "util/str.h"
|
2018-01-22 18:22:31 +08:00
|
|
|
|
2021-11-13 06:24:12 +08:00
|
|
|
#define SC_SERVER_FILENAME "scrcpy-server"
|
2018-01-23 22:46:34 +08:00
|
|
|
|
2021-11-13 06:24:12 +08:00
|
|
|
#define SC_SERVER_PATH_DEFAULT PREFIX "/share/scrcpy/" SC_SERVER_FILENAME
|
|
|
|
#define SC_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__
|
2021-11-13 06:08:19 +08:00
|
|
|
char *server_path = sc_str_from_wchars(server_path_env);
|
2019-12-14 14:34:49 +08:00
|
|
|
#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) {
|
2021-11-25 05:06:11 +08:00
|
|
|
LOG_OOM();
|
2019-12-15 01:13:56 +08:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
LOGD("Using SCRCPY_SERVER_PATH: %s", server_path);
|
|
|
|
return server_path;
|
2019-06-10 21:14:10 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
#ifndef PORTABLE
|
2021-11-13 06:24:12 +08:00
|
|
|
LOGD("Using server: " SC_SERVER_PATH_DEFAULT);
|
|
|
|
char *server_path = strdup(SC_SERVER_PATH_DEFAULT);
|
2019-12-15 01:13:56 +08:00
|
|
|
if (!server_path) {
|
2021-11-25 05:06:11 +08:00
|
|
|
LOG_OOM();
|
2019-12-15 01:13:56 +08:00
|
|
|
return NULL;
|
|
|
|
}
|
2019-06-10 21:14:10 +08:00
|
|
|
#else
|
2021-11-13 06:24:12 +08:00
|
|
|
char *server_path = sc_file_get_local_path(SC_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, "
|
2021-11-13 06:24:12 +08:00
|
|
|
"using " SC_SERVER_FILENAME " from current directory");
|
|
|
|
return strdup(SC_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
|
2021-11-13 06:24:12 +08:00
|
|
|
sc_server_params_destroy(struct sc_server_params *params) {
|
2021-10-28 05:40:52 +08:00
|
|
|
// The server stores a copy of the params provided by the user
|
2022-02-05 03:49:35 +08:00
|
|
|
free((char *) params->req_serial);
|
2021-10-28 05:40:52 +08:00
|
|
|
free((char *) params->crop);
|
|
|
|
free((char *) params->codec_options);
|
|
|
|
free((char *) params->encoder_name);
|
2021-11-26 05:22:49 +08:00
|
|
|
free((char *) params->tcpip_dst);
|
2021-10-28 05:40:52 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
2021-11-13 06:24:12 +08:00
|
|
|
sc_server_params_copy(struct sc_server_params *dst,
|
|
|
|
const struct sc_server_params *src) {
|
2021-10-28 05:40:52 +08:00
|
|
|
*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; \
|
|
|
|
} \
|
|
|
|
}
|
|
|
|
|
2022-02-05 03:49:35 +08:00
|
|
|
COPY(req_serial);
|
2021-10-28 05:40:52 +08:00
|
|
|
COPY(crop);
|
|
|
|
COPY(codec_options);
|
|
|
|
COPY(encoder_name);
|
2021-11-26 05:22:49 +08:00
|
|
|
COPY(tcpip_dst);
|
2021-10-28 05:40:52 +08:00
|
|
|
#undef COPY
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
error:
|
2021-11-13 06:24:12 +08:00
|
|
|
sc_server_params_destroy(dst);
|
2021-10-28 05:40:52 +08:00
|
|
|
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;
|
|
|
|
}
|
2022-02-04 06:04:01 +08:00
|
|
|
bool ok = sc_adb_push(intr, serial, server_path, SC_DEVICE_SERVER_PATH, 0);
|
2021-01-24 22:14:53 +08:00
|
|
|
free(server_path);
|
2021-11-19 05:11:19 +08:00
|
|
|
return ok;
|
2018-01-23 22:46:34 +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-25 05:57:36 +08:00
|
|
|
static bool
|
|
|
|
sc_server_sleep(struct sc_server *server, sc_tick deadline) {
|
|
|
|
sc_mutex_lock(&server->mutex);
|
|
|
|
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);
|
|
|
|
|
|
|
|
return !stopped;
|
|
|
|
}
|
|
|
|
|
2021-11-12 00:48:41 +08:00
|
|
|
static sc_pid
|
2021-11-13 06:24:12 +08:00
|
|
|
execute_server(struct sc_server *server,
|
|
|
|
const struct sc_server_params *params) {
|
2021-11-25 04:10:18 +08:00
|
|
|
sc_pid pid = SC_PROCESS_NONE;
|
|
|
|
|
2022-02-05 03:49:35 +08:00
|
|
|
const char *serial = server->serial;
|
2022-02-05 17:07:13 +08:00
|
|
|
assert(serial);
|
|
|
|
|
2021-11-25 04:10:18 +08:00
|
|
|
const char *cmd[128];
|
|
|
|
unsigned count = 0;
|
2022-02-05 17:07:13 +08:00
|
|
|
cmd[count++] = sc_adb_get_executable();
|
|
|
|
cmd[count++] = "-s";
|
|
|
|
cmd[count++] = serial;
|
2021-11-25 04:10:18 +08:00
|
|
|
cmd[count++] = "shell";
|
|
|
|
cmd[count++] = "CLASSPATH=" SC_DEVICE_SERVER_PATH;
|
|
|
|
cmd[count++] = "app_process";
|
|
|
|
|
2019-11-04 02:31:56 +08:00
|
|
|
#ifdef SERVER_DEBUGGER
|
|
|
|
# define SERVER_DEBUGGER_PORT "5005"
|
2021-11-25 04:10:18 +08:00
|
|
|
cmd[count++] =
|
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
|
2021-11-25 04:10:18 +08:00
|
|
|
SERVER_DEBUGGER_PORT;
|
2019-11-04 02:31:56 +08:00
|
|
|
#endif
|
2021-11-25 04:10:18 +08:00
|
|
|
cmd[count++] = "/"; // unused
|
|
|
|
cmd[count++] = "com.genymobile.scrcpy.Server";
|
|
|
|
cmd[count++] = SCRCPY_VERSION;
|
|
|
|
|
|
|
|
unsigned dyn_idx = count; // from there, the strings are allocated
|
|
|
|
#define ADD_PARAM(fmt, ...) { \
|
|
|
|
char *p = (char *) &cmd[count]; \
|
|
|
|
if (asprintf(&p, fmt, ## __VA_ARGS__) == -1) { \
|
|
|
|
goto end; \
|
|
|
|
} \
|
|
|
|
cmd[count++] = p; \
|
|
|
|
}
|
|
|
|
|
2021-11-25 04:23:20 +08:00
|
|
|
ADD_PARAM("log_level=%s", log_level_to_server_string(params->log_level));
|
|
|
|
ADD_PARAM("bit_rate=%" PRIu32, params->bit_rate);
|
2021-11-25 04:31:12 +08:00
|
|
|
|
|
|
|
if (params->max_size) {
|
|
|
|
ADD_PARAM("max_size=%" PRIu16, params->max_size);
|
|
|
|
}
|
|
|
|
if (params->max_fps) {
|
|
|
|
ADD_PARAM("max_fps=%" PRIu16, params->max_fps);
|
|
|
|
}
|
|
|
|
if (params->lock_video_orientation != SC_LOCK_VIDEO_ORIENTATION_UNLOCKED) {
|
|
|
|
ADD_PARAM("lock_video_orientation=%" PRIi8,
|
|
|
|
params->lock_video_orientation);
|
|
|
|
}
|
|
|
|
if (server->tunnel.forward) {
|
2022-01-16 05:57:38 +08:00
|
|
|
ADD_PARAM("tunnel_forward=true");
|
2021-11-25 04:31:12 +08:00
|
|
|
}
|
|
|
|
if (params->crop) {
|
|
|
|
ADD_PARAM("crop=%s", params->crop);
|
|
|
|
}
|
|
|
|
if (!params->control) {
|
|
|
|
// By default, control is true
|
2022-01-16 05:57:38 +08:00
|
|
|
ADD_PARAM("control=false");
|
2021-11-25 04:31:12 +08:00
|
|
|
}
|
|
|
|
if (params->display_id) {
|
|
|
|
ADD_PARAM("display_id=%" PRIu32, params->display_id);
|
|
|
|
}
|
|
|
|
if (params->show_touches) {
|
2022-01-16 05:57:38 +08:00
|
|
|
ADD_PARAM("show_touches=true");
|
2021-11-25 04:31:12 +08:00
|
|
|
}
|
|
|
|
if (params->stay_awake) {
|
2022-01-16 05:57:38 +08:00
|
|
|
ADD_PARAM("stay_awake=true");
|
2021-11-25 04:31:12 +08:00
|
|
|
}
|
|
|
|
if (params->codec_options) {
|
|
|
|
ADD_PARAM("codec_options=%s", params->codec_options);
|
|
|
|
}
|
|
|
|
if (params->encoder_name) {
|
|
|
|
ADD_PARAM("encoder_name=%s", params->encoder_name);
|
|
|
|
}
|
|
|
|
if (params->power_off_on_close) {
|
2022-01-16 05:57:38 +08:00
|
|
|
ADD_PARAM("power_off_on_close=true");
|
2021-11-25 04:31:12 +08:00
|
|
|
}
|
|
|
|
if (!params->clipboard_autosync) {
|
2021-12-16 01:27:45 +08:00
|
|
|
// By default, clipboard_autosync is true
|
2022-01-16 05:57:38 +08:00
|
|
|
ADD_PARAM("clipboard_autosync=false");
|
2021-11-25 04:31:12 +08:00
|
|
|
}
|
2022-01-16 06:01:14 +08:00
|
|
|
if (!params->downsize_on_error) {
|
|
|
|
// By default, downsize_on_error is true
|
|
|
|
ADD_PARAM("downsize_on_error=false");
|
|
|
|
}
|
2021-11-25 04:10:18 +08:00
|
|
|
|
|
|
|
#undef ADD_PARAM
|
|
|
|
|
2022-02-05 17:07:13 +08:00
|
|
|
cmd[count++] = NULL;
|
|
|
|
|
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-11-25 05:27:28 +08:00
|
|
|
// Inherit both stdout and stderr (all server logs are printed to stdout)
|
2022-02-05 17:07:13 +08:00
|
|
|
pid = sc_adb_execute(cmd, 0);
|
2021-11-25 04:10:18 +08:00
|
|
|
|
|
|
|
end:
|
|
|
|
for (unsigned i = dyn_idx; i < count; ++i) {
|
|
|
|
free((char *) cmd[i]);
|
|
|
|
}
|
|
|
|
|
|
|
|
return pid;
|
2018-01-22 18:22:31 +08:00
|
|
|
}
|
|
|
|
|
2021-11-01 05:01:57 +08:00
|
|
|
static bool
|
2021-11-18 08:02:53 +08:00
|
|
|
connect_and_read_byte(struct sc_intr *intr, sc_socket socket,
|
|
|
|
uint32_t tunnel_host, uint16_t tunnel_port) {
|
|
|
|
bool ok = net_connect_intr(intr, socket, tunnel_host, tunnel_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-11-26 04:54:08 +08:00
|
|
|
connect_to_server(struct sc_server *server, unsigned attempts, sc_tick delay,
|
2021-11-18 08:02:53 +08:00
|
|
|
uint32_t host, uint16_t port) {
|
2018-03-12 15:35:51 +08:00
|
|
|
do {
|
2021-11-26 04:54:08 +08:00
|
|
|
LOGD("Remaining connection attempts: %u", attempts);
|
2021-11-01 05:01:57 +08:00
|
|
|
sc_socket socket = net_socket();
|
2021-11-13 16:58:52 +08:00
|
|
|
if (socket != SC_SOCKET_NONE) {
|
2021-11-18 08:02:53 +08:00
|
|
|
bool ok = connect_and_read_byte(&server->intr, socket, host, 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
|
|
|
}
|
2021-11-14 22:39:20 +08:00
|
|
|
|
|
|
|
if (sc_intr_is_interrupted(&server->intr)) {
|
|
|
|
// Stop immediately
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2018-03-12 15:35:51 +08:00
|
|
|
if (attempts) {
|
2021-10-31 21:56:37 +08:00
|
|
|
sc_tick deadline = sc_tick_now() + delay;
|
2021-11-25 05:57:36 +08:00
|
|
|
bool ok = sc_server_sleep(server, deadline);
|
|
|
|
if (!ok) {
|
2021-10-31 21:56:37 +08:00
|
|
|
LOGI("Connection attempt stopped");
|
|
|
|
break;
|
|
|
|
}
|
2018-03-12 15:35:51 +08:00
|
|
|
}
|
2021-11-26 04:54:08 +08:00
|
|
|
} while (--attempts);
|
2021-11-13 16:58:52 +08:00
|
|
|
return SC_SOCKET_NONE;
|
2018-03-12 15:35:51 +08:00
|
|
|
}
|
|
|
|
|
2021-01-01 23:34:47 +08:00
|
|
|
bool
|
2021-11-13 06:24:12 +08:00
|
|
|
sc_server_init(struct sc_server *server, const struct sc_server_params *params,
|
|
|
|
const struct sc_server_callbacks *cbs, void *cbs_userdata) {
|
|
|
|
bool ok = sc_server_params_copy(&server->params, params);
|
2021-10-28 05:40:52 +08:00
|
|
|
if (!ok) {
|
2021-11-25 05:06:11 +08:00
|
|
|
LOG_OOM();
|
2021-10-28 05:40:52 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2021-10-31 21:56:37 +08:00
|
|
|
ok = sc_mutex_init(&server->mutex);
|
|
|
|
if (!ok) {
|
2021-11-13 06:24:12 +08:00
|
|
|
sc_server_params_destroy(&server->params);
|
2021-10-31 21:56:37 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
ok = sc_cond_init(&server->cond_stopped);
|
|
|
|
if (!ok) {
|
|
|
|
sc_mutex_destroy(&server->mutex);
|
2021-11-13 06:24:12 +08:00
|
|
|
sc_server_params_destroy(&server->params);
|
2021-10-31 21:56:37 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2021-11-13 01:50:50 +08:00
|
|
|
ok = sc_intr_init(&server->intr);
|
|
|
|
if (!ok) {
|
|
|
|
sc_cond_destroy(&server->cond_stopped);
|
|
|
|
sc_mutex_destroy(&server->mutex);
|
2021-11-13 06:24:12 +08:00
|
|
|
sc_server_params_destroy(&server->params);
|
2021-11-13 01:50:50 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2022-02-05 03:49:35 +08:00
|
|
|
server->serial = NULL;
|
2021-10-31 21:56:37 +08:00
|
|
|
server->stopped = false;
|
2021-01-01 23:34:47 +08:00
|
|
|
|
2021-11-13 16:58:52 +08:00
|
|
|
server->video_socket = SC_SOCKET_NONE;
|
|
|
|
server->control_socket = SC_SOCKET_NONE;
|
2021-01-01 23:34:47 +08:00
|
|
|
|
2021-11-13 05:32:29 +08:00
|
|
|
sc_adb_tunnel_init(&server->tunnel);
|
2021-01-01 23:34:47 +08:00
|
|
|
|
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,
|
2021-11-13 06:24:12 +08:00
|
|
|
struct sc_server_info *info) {
|
|
|
|
unsigned char buf[SC_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-11-13 06:24:12 +08:00
|
|
|
if (r < SC_DEVICE_NAME_FIELD_LENGTH + 4) {
|
2021-05-09 22:52:22 +08:00
|
|
|
LOGE("Could not retrieve device information");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
// in case the client sends garbage
|
2021-11-13 06:24:12 +08:00
|
|
|
buf[SC_DEVICE_NAME_FIELD_LENGTH - 1] = '\0';
|
2021-10-31 01:07:35 +08:00
|
|
|
memcpy(info->device_name, (char *) buf, sizeof(info->device_name));
|
|
|
|
|
2021-11-13 06:24:12 +08:00
|
|
|
info->frame_size.width = (buf[SC_DEVICE_NAME_FIELD_LENGTH] << 8)
|
|
|
|
| buf[SC_DEVICE_NAME_FIELD_LENGTH + 1];
|
|
|
|
info->frame_size.height = (buf[SC_DEVICE_NAME_FIELD_LENGTH + 2] << 8)
|
|
|
|
| buf[SC_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-11-13 06:24:12 +08:00
|
|
|
sc_server_connect_to(struct sc_server *server, struct sc_server_info *info) {
|
2021-11-13 05:32:29 +08:00
|
|
|
struct sc_adb_tunnel *tunnel = &server->tunnel;
|
|
|
|
|
|
|
|
assert(tunnel->enabled);
|
|
|
|
|
2022-02-05 03:49:35 +08:00
|
|
|
const char *serial = server->serial;
|
|
|
|
assert(serial);
|
|
|
|
|
2021-12-07 04:50:24 +08:00
|
|
|
bool control = server->params.control;
|
2021-11-01 18:44:58 +08:00
|
|
|
|
2021-11-13 16:58:52 +08:00
|
|
|
sc_socket video_socket = SC_SOCKET_NONE;
|
|
|
|
sc_socket control_socket = SC_SOCKET_NONE;
|
2021-11-13 05:32:29 +08:00
|
|
|
if (!tunnel->forward) {
|
|
|
|
video_socket = net_accept_intr(&server->intr, tunnel->server_socket);
|
2021-11-13 16:58:52 +08:00
|
|
|
if (video_socket == SC_SOCKET_NONE) {
|
2021-11-01 18:44:58 +08:00
|
|
|
goto fail;
|
2019-05-29 03:03:54 +08:00
|
|
|
}
|
|
|
|
|
2021-12-07 04:50:24 +08:00
|
|
|
if (control) {
|
|
|
|
control_socket =
|
|
|
|
net_accept_intr(&server->intr, tunnel->server_socket);
|
|
|
|
if (control_socket == SC_SOCKET_NONE) {
|
|
|
|
goto fail;
|
|
|
|
}
|
2019-05-29 03:02:57 +08:00
|
|
|
}
|
2018-03-12 15:35:51 +08:00
|
|
|
} else {
|
2021-11-18 08:02:53 +08:00
|
|
|
uint32_t tunnel_host = server->params.tunnel_host;
|
|
|
|
if (!tunnel_host) {
|
|
|
|
tunnel_host = IPV4_LOCALHOST;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint16_t tunnel_port = server->params.tunnel_port;
|
|
|
|
if (!tunnel_port) {
|
|
|
|
tunnel_port = tunnel->local_port;
|
|
|
|
}
|
|
|
|
|
2021-11-26 04:54:08 +08:00
|
|
|
unsigned attempts = 100;
|
2021-10-31 21:56:37 +08:00
|
|
|
sc_tick delay = SC_TICK_FROM_MS(100);
|
2021-11-18 08:02:53 +08:00
|
|
|
video_socket = connect_to_server(server, attempts, delay, tunnel_host,
|
|
|
|
tunnel_port);
|
2021-11-13 16:58:52 +08:00
|
|
|
if (video_socket == SC_SOCKET_NONE) {
|
2021-11-01 18:44:58 +08:00
|
|
|
goto fail;
|
2019-05-29 03:03:54 +08:00
|
|
|
}
|
|
|
|
|
2021-12-07 04:50:24 +08:00
|
|
|
if (control) {
|
|
|
|
// we know that the device is listening, we don't need several
|
|
|
|
// attempts
|
|
|
|
control_socket = net_socket();
|
|
|
|
if (control_socket == SC_SOCKET_NONE) {
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
bool ok = net_connect_intr(&server->intr, control_socket,
|
|
|
|
tunnel_host, tunnel_port);
|
|
|
|
if (!ok) {
|
|
|
|
goto fail;
|
|
|
|
}
|
2021-11-01 05:01:57 +08:00
|
|
|
}
|
2018-03-12 15:35:51 +08:00
|
|
|
}
|
2018-02-09 00:38:38 +08:00
|
|
|
|
|
|
|
// we don't need the adb tunnel anymore
|
2021-11-13 05:32:29 +08:00
|
|
|
sc_adb_tunnel_close(tunnel, &server->intr, serial);
|
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;
|
|
|
|
}
|
|
|
|
|
2021-11-13 16:58:52 +08:00
|
|
|
assert(video_socket != SC_SOCKET_NONE);
|
2021-12-07 04:50:24 +08:00
|
|
|
assert(!control || control_socket != SC_SOCKET_NONE);
|
2021-11-01 18:44:58 +08:00
|
|
|
|
|
|
|
server->video_socket = video_socket;
|
|
|
|
server->control_socket = control_socket;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
fail:
|
2021-11-13 16:58:52 +08:00
|
|
|
if (video_socket != SC_SOCKET_NONE) {
|
2021-11-01 18:44:58 +08:00
|
|
|
if (!net_close(video_socket)) {
|
|
|
|
LOGW("Could not close video socket");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-11-13 16:58:52 +08:00
|
|
|
if (control_socket != SC_SOCKET_NONE) {
|
2021-11-01 18:44:58 +08:00
|
|
|
if (!net_close(control_socket)) {
|
|
|
|
LOGW("Could not close control socket");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-02-12 19:44:02 +08:00
|
|
|
if (tunnel->enabled) {
|
|
|
|
// Always leave this function with tunnel disabled
|
|
|
|
sc_adb_tunnel_close(tunnel, &server->intr, serial);
|
|
|
|
}
|
2021-10-30 21:33:23 +08:00
|
|
|
|
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
|
2021-11-13 06:24:12 +08:00
|
|
|
sc_server_on_terminated(void *userdata) {
|
|
|
|
struct sc_server *server = userdata;
|
2021-11-13 01:30:20 +08:00
|
|
|
|
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-11-26 05:22:49 +08:00
|
|
|
static bool
|
2022-02-05 03:49:35 +08:00
|
|
|
is_tcpip_mode_enabled(struct sc_server *server, const char *serial) {
|
2021-11-26 05:22:49 +08:00
|
|
|
struct sc_intr *intr = &server->intr;
|
|
|
|
|
|
|
|
char *current_port =
|
2022-02-04 06:04:01 +08:00
|
|
|
sc_adb_getprop(intr, serial, "service.adb.tcp.port", SC_ADB_SILENT);
|
2021-11-26 05:22:49 +08:00
|
|
|
if (!current_port) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Is the device is listening on TCP on port 5555?
|
|
|
|
bool enabled = !strcmp("5555", current_port);
|
|
|
|
free(current_port);
|
|
|
|
return enabled;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
2022-02-05 03:49:35 +08:00
|
|
|
wait_tcpip_mode_enabled(struct sc_server *server, const char *serial,
|
|
|
|
unsigned attempts, sc_tick delay) {
|
|
|
|
if (is_tcpip_mode_enabled(server, serial)) {
|
2021-11-26 05:22:49 +08:00
|
|
|
LOGI("TCP/IP mode enabled");
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Only print this log if TCP/IP is not enabled
|
|
|
|
LOGI("Waiting for TCP/IP mode enabled...");
|
|
|
|
|
|
|
|
do {
|
|
|
|
sc_tick deadline = sc_tick_now() + delay;
|
|
|
|
if (!sc_server_sleep(server, deadline)) {
|
|
|
|
LOGI("TCP/IP mode waiting interrupted");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2022-02-05 03:49:35 +08:00
|
|
|
if (is_tcpip_mode_enabled(server, serial)) {
|
2021-11-26 05:22:49 +08:00
|
|
|
LOGI("TCP/IP mode enabled");
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
} while (--attempts);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
char *
|
|
|
|
append_port_5555(const char *ip) {
|
|
|
|
size_t len = strlen(ip);
|
|
|
|
|
|
|
|
// sizeof counts the final '\0'
|
|
|
|
char *ip_port = malloc(len + sizeof(":5555"));
|
|
|
|
if (!ip_port) {
|
|
|
|
LOG_OOM();
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
memcpy(ip_port, ip, len);
|
|
|
|
memcpy(ip_port + len, ":5555", sizeof(":5555"));
|
|
|
|
|
|
|
|
return ip_port;
|
|
|
|
}
|
|
|
|
|
2022-02-05 02:42:42 +08:00
|
|
|
static char *
|
2022-02-05 03:49:35 +08:00
|
|
|
sc_server_switch_to_tcpip(struct sc_server *server, const char *serial) {
|
2021-11-26 05:22:49 +08:00
|
|
|
assert(serial);
|
|
|
|
|
|
|
|
struct sc_intr *intr = &server->intr;
|
|
|
|
|
2022-02-05 03:49:35 +08:00
|
|
|
LOGI("Switching device %s to TCP/IP...", serial);
|
|
|
|
|
2022-02-04 06:04:01 +08:00
|
|
|
char *ip = sc_adb_get_device_ip(intr, serial, 0);
|
2021-11-26 05:22:49 +08:00
|
|
|
if (!ip) {
|
|
|
|
LOGE("Device IP not found");
|
2022-02-05 02:42:42 +08:00
|
|
|
return NULL;
|
2021-11-26 05:22:49 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
char *ip_port = append_port_5555(ip);
|
|
|
|
free(ip);
|
|
|
|
if (!ip_port) {
|
2022-02-05 02:42:42 +08:00
|
|
|
return NULL;
|
2021-11-26 05:22:49 +08:00
|
|
|
}
|
|
|
|
|
2022-02-05 03:49:35 +08:00
|
|
|
bool tcp_mode = is_tcpip_mode_enabled(server, serial);
|
2021-11-26 05:22:49 +08:00
|
|
|
|
|
|
|
if (!tcp_mode) {
|
2022-02-04 06:04:01 +08:00
|
|
|
bool ok = sc_adb_tcpip(intr, serial, 5555, SC_ADB_NO_STDOUT);
|
2021-11-26 05:22:49 +08:00
|
|
|
if (!ok) {
|
|
|
|
LOGE("Could not restart adbd in TCP/IP mode");
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned attempts = 40;
|
|
|
|
sc_tick delay = SC_TICK_FROM_MS(250);
|
2022-02-05 03:49:35 +08:00
|
|
|
ok = wait_tcpip_mode_enabled(server, serial, attempts, delay);
|
2021-11-26 05:22:49 +08:00
|
|
|
if (!ok) {
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-02-05 02:42:42 +08:00
|
|
|
return ip_port;
|
2021-11-26 05:22:49 +08:00
|
|
|
|
|
|
|
error:
|
|
|
|
free(ip_port);
|
2022-02-05 02:42:42 +08:00
|
|
|
return NULL;
|
2021-11-26 05:22:49 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
|
|
|
sc_server_connect_to_tcpip(struct sc_server *server, const char *ip_port) {
|
|
|
|
struct sc_intr *intr = &server->intr;
|
|
|
|
|
|
|
|
// Error expected if not connected, do not report any error
|
2022-02-04 06:04:01 +08:00
|
|
|
sc_adb_disconnect(intr, ip_port, SC_ADB_SILENT);
|
2021-11-26 05:22:49 +08:00
|
|
|
|
2022-02-05 03:49:35 +08:00
|
|
|
LOGI("Connecting to %s...", ip_port);
|
|
|
|
|
2022-02-04 06:04:01 +08:00
|
|
|
bool ok = sc_adb_connect(intr, ip_port, 0);
|
2021-11-26 05:22:49 +08:00
|
|
|
if (!ok) {
|
|
|
|
LOGE("Could not connect to %s", ip_port);
|
|
|
|
return false;
|
2021-11-18 04:58:36 +08:00
|
|
|
}
|
|
|
|
|
2021-11-26 05:22:49 +08:00
|
|
|
LOGI("Connected to %s", ip_port);
|
2021-11-18 04:58:36 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2021-11-26 05:22:49 +08:00
|
|
|
static bool
|
2022-02-06 04:20:12 +08:00
|
|
|
sc_server_configure_tcpip_known_address(struct sc_server *server,
|
|
|
|
const char *addr) {
|
|
|
|
// Append ":5555" if no port is present
|
|
|
|
bool contains_port = strchr(addr, ':');
|
|
|
|
char *ip_port = contains_port ? strdup(addr) : append_port_5555(addr);
|
|
|
|
if (!ip_port) {
|
|
|
|
LOG_OOM();
|
|
|
|
return false;
|
|
|
|
}
|
2021-11-26 05:22:49 +08:00
|
|
|
|
2022-02-06 04:20:12 +08:00
|
|
|
server->serial = ip_port;
|
|
|
|
return sc_server_connect_to_tcpip(server, ip_port);
|
|
|
|
}
|
2021-11-26 05:22:49 +08:00
|
|
|
|
2022-02-06 04:20:12 +08:00
|
|
|
static bool
|
|
|
|
sc_server_configure_tcpip_unknown_address(struct sc_server *server,
|
|
|
|
const char *serial) {
|
2022-02-06 22:02:29 +08:00
|
|
|
bool is_already_tcpip = sc_adb_is_serial_tcpip(serial);
|
2022-02-06 04:20:12 +08:00
|
|
|
if (is_already_tcpip) {
|
|
|
|
// Nothing to do
|
|
|
|
LOGI("Device already connected via TCP/IP: %s", serial);
|
|
|
|
return true;
|
|
|
|
}
|
2021-11-26 05:22:49 +08:00
|
|
|
|
2022-02-06 04:20:12 +08:00
|
|
|
char *ip_port = sc_server_switch_to_tcpip(server, serial);
|
|
|
|
if (!ip_port) {
|
|
|
|
return false;
|
2021-11-26 05:22:49 +08:00
|
|
|
}
|
|
|
|
|
2022-02-05 03:49:35 +08:00
|
|
|
server->serial = ip_port;
|
|
|
|
return sc_server_connect_to_tcpip(server, ip_port);
|
2021-11-26 05:22:49 +08:00
|
|
|
}
|
|
|
|
|
2021-10-30 21:33:23 +08:00
|
|
|
static int
|
|
|
|
run_server(void *data) {
|
2021-11-13 06:24:12 +08:00
|
|
|
struct sc_server *server = data;
|
2021-10-30 21:33:23 +08:00
|
|
|
|
2021-11-26 05:22:49 +08:00
|
|
|
const struct sc_server_params *params = &server->params;
|
|
|
|
|
2022-02-06 22:28:23 +08:00
|
|
|
// Execute "adb start-server" before "adb devices" so that daemon starting
|
|
|
|
// output/errors is correctly printed in the console ("adb devices" output
|
|
|
|
// is parsed, so it is not output)
|
|
|
|
bool ok = sc_adb_start_server(&server->intr, 0);
|
|
|
|
if (!ok) {
|
|
|
|
LOGE("Could not start adb daemon");
|
|
|
|
goto error_connection_failed;
|
|
|
|
}
|
|
|
|
|
2022-02-06 04:20:12 +08:00
|
|
|
// params->tcpip_dst implies params->tcpip
|
|
|
|
assert(!params->tcpip_dst || params->tcpip);
|
|
|
|
|
|
|
|
// If tcpip_dst parameter is given, then it must connect to this address.
|
|
|
|
// Therefore, the device is unknown, so serial is meaningless at this point.
|
|
|
|
assert(!params->req_serial || !params->tcpip_dst);
|
|
|
|
|
|
|
|
// A device must be selected via a serial in all cases except when --tcpip=
|
|
|
|
// is called with a parameter (in that case, the device may initially not
|
|
|
|
// exist, and scrcpy will execute "adb connect").
|
|
|
|
bool need_initial_serial = !params->tcpip_dst;
|
|
|
|
|
|
|
|
if (need_initial_serial) {
|
2022-02-07 01:40:18 +08:00
|
|
|
// At most one of the 3 following parameters may be set
|
|
|
|
assert(!!params->req_serial
|
|
|
|
+ params->select_usb
|
|
|
|
+ params->select_tcpip <= 1);
|
|
|
|
|
2022-02-06 23:06:46 +08:00
|
|
|
struct sc_adb_device_selector selector;
|
|
|
|
if (params->req_serial) {
|
|
|
|
selector.type = SC_ADB_DEVICE_SELECT_SERIAL;
|
|
|
|
selector.serial = params->req_serial;
|
2022-02-07 01:40:18 +08:00
|
|
|
} else if (params->select_usb) {
|
|
|
|
selector.type = SC_ADB_DEVICE_SELECT_USB;
|
|
|
|
} else if (params->select_tcpip) {
|
|
|
|
selector.type = SC_ADB_DEVICE_SELECT_TCPIP;
|
2022-02-06 23:06:46 +08:00
|
|
|
} else {
|
|
|
|
selector.type = SC_ADB_DEVICE_SELECT_ALL;
|
|
|
|
}
|
2022-02-06 22:04:00 +08:00
|
|
|
struct sc_adb_device device;
|
2022-02-06 23:06:46 +08:00
|
|
|
ok = sc_adb_select_device(&server->intr, &selector, 0, &device);
|
2022-02-06 22:04:00 +08:00
|
|
|
if (!ok) {
|
2021-11-26 05:22:49 +08:00
|
|
|
goto error_connection_failed;
|
|
|
|
}
|
2022-02-06 04:20:12 +08:00
|
|
|
|
|
|
|
if (params->tcpip) {
|
|
|
|
assert(!params->tcpip_dst);
|
2022-02-06 22:04:00 +08:00
|
|
|
ok = sc_server_configure_tcpip_unknown_address(server,
|
|
|
|
device.serial);
|
|
|
|
sc_adb_device_destroy(&device);
|
2022-02-06 04:20:12 +08:00
|
|
|
if (!ok) {
|
|
|
|
goto error_connection_failed;
|
|
|
|
}
|
|
|
|
assert(server->serial);
|
|
|
|
} else {
|
2022-02-06 22:04:00 +08:00
|
|
|
// "move" the device.serial without copy
|
|
|
|
server->serial = device.serial;
|
|
|
|
// the serial must not be freed by the destructor
|
|
|
|
device.serial = NULL;
|
|
|
|
sc_adb_device_destroy(&device);
|
2022-02-06 04:20:12 +08:00
|
|
|
}
|
2022-02-05 03:49:35 +08:00
|
|
|
} else {
|
2022-02-06 04:20:12 +08:00
|
|
|
ok = sc_server_configure_tcpip_known_address(server, params->tcpip_dst);
|
|
|
|
if (!ok) {
|
2022-02-05 03:49:35 +08:00
|
|
|
goto error_connection_failed;
|
|
|
|
}
|
2021-11-26 05:22:49 +08:00
|
|
|
}
|
2021-11-13 01:30:20 +08:00
|
|
|
|
2022-02-05 03:49:35 +08:00
|
|
|
const char *serial = server->serial;
|
|
|
|
assert(serial);
|
|
|
|
LOGD("Device serial: %s", serial);
|
2021-11-18 04:58:36 +08:00
|
|
|
|
2022-02-06 04:20:12 +08:00
|
|
|
ok = push_server(&server->intr, serial);
|
2021-10-30 21:33:23 +08:00
|
|
|
if (!ok) {
|
|
|
|
goto error_connection_failed;
|
2021-11-13 01:30:20 +08:00
|
|
|
}
|
|
|
|
|
2022-02-05 03:49:35 +08:00
|
|
|
ok = sc_adb_tunnel_open(&server->tunnel, &server->intr, serial,
|
2021-11-13 05:32:29 +08:00
|
|
|
params->port_range, params->force_adb_forward);
|
2021-10-30 21:33:23 +08:00
|
|
|
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) {
|
2022-02-05 03:49:35 +08:00
|
|
|
sc_adb_tunnel_close(&server->tunnel, &server->intr, serial);
|
2021-10-30 21:33:23 +08:00
|
|
|
goto error_connection_failed;
|
2021-11-13 01:30:20 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static const struct sc_process_listener listener = {
|
2021-11-13 06:24:12 +08:00
|
|
|
.on_terminated = sc_server_on_terminated,
|
2021-11-13 01:30:20 +08:00
|
|
|
};
|
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
|
2022-02-05 03:49:35 +08:00
|
|
|
sc_adb_tunnel_close(&server->tunnel, &server->intr, serial);
|
2021-10-30 21:33:23 +08:00
|
|
|
goto error_connection_failed;
|
2021-11-13 01:30:20 +08:00
|
|
|
}
|
|
|
|
|
2021-11-13 06:24:12 +08:00
|
|
|
ok = sc_server_connect_to(server, &server->info);
|
2021-10-30 21:33:23 +08:00
|
|
|
// 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-12-09 06:20:17 +08:00
|
|
|
// Interrupt sockets to wake up socket blocking calls on the server
|
|
|
|
assert(server->video_socket != SC_SOCKET_NONE);
|
|
|
|
net_interrupt(server->video_socket);
|
|
|
|
|
|
|
|
if (server->control_socket != SC_SOCKET_NONE) {
|
|
|
|
// There is no control_socket if --no-control is set
|
|
|
|
net_interrupt(server->control_socket);
|
|
|
|
}
|
|
|
|
|
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
|
2021-11-13 06:24:12 +08:00
|
|
|
sc_server_start(struct sc_server *server) {
|
2021-12-10 04:32:11 +08:00
|
|
|
bool ok =
|
|
|
|
sc_thread_create(&server->thread, run_server, "scrcpy-server", server);
|
2021-10-30 21:33:23 +08:00
|
|
|
if (!ok) {
|
|
|
|
LOGE("Could not create server thread");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2021-11-13 06:24:12 +08:00
|
|
|
sc_server_stop(struct sc_server *server) {
|
2021-10-30 21:33:23 +08:00
|
|
|
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
|
2021-11-13 06:24:12 +08:00
|
|
|
sc_server_destroy(struct sc_server *server) {
|
2022-01-28 06:22:43 +08:00
|
|
|
if (server->video_socket != SC_SOCKET_NONE) {
|
|
|
|
net_close(server->video_socket);
|
|
|
|
}
|
|
|
|
if (server->control_socket != SC_SOCKET_NONE) {
|
|
|
|
net_close(server->control_socket);
|
|
|
|
}
|
|
|
|
|
2022-02-05 03:49:35 +08:00
|
|
|
free(server->serial);
|
2021-11-13 06:24:12 +08:00
|
|
|
sc_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
|
|
|
}
|