|
|
|
@ -4,6 +4,7 @@
|
|
|
|
#include <inttypes.h>
|
|
|
|
#include <inttypes.h>
|
|
|
|
#include <stdint.h>
|
|
|
|
#include <stdint.h>
|
|
|
|
#include <SDL2/SDL_assert.h>
|
|
|
|
#include <SDL2/SDL_assert.h>
|
|
|
|
|
|
|
|
#include <SDL2/SDL_timer.h>
|
|
|
|
|
|
|
|
|
|
|
|
#include "config.h"
|
|
|
|
#include "config.h"
|
|
|
|
#include "log.h"
|
|
|
|
#include "log.h"
|
|
|
|
@ -37,17 +38,45 @@ static SDL_bool remove_server(const char *serial) {
|
|
|
|
return process_check_success(process, "adb shell rm");
|
|
|
|
return process_check_success(process, "adb shell rm");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static SDL_bool enable_tunnel(const char *serial, Uint16 local_port) {
|
|
|
|
static SDL_bool enable_tunnel_reverse(const char *serial, Uint16 local_port) {
|
|
|
|
process_t process = adb_reverse(serial, SOCKET_NAME, local_port);
|
|
|
|
process_t process = adb_reverse(serial, SOCKET_NAME, local_port);
|
|
|
|
return process_check_success(process, "adb reverse");
|
|
|
|
return process_check_success(process, "adb reverse");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static SDL_bool disable_tunnel(const char *serial) {
|
|
|
|
static SDL_bool disable_tunnel_reverse(const char *serial) {
|
|
|
|
process_t process = adb_reverse_remove(serial, SOCKET_NAME);
|
|
|
|
process_t process = adb_reverse_remove(serial, SOCKET_NAME);
|
|
|
|
return process_check_success(process, "adb reverse --remove");
|
|
|
|
return process_check_success(process, "adb reverse --remove");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static process_t execute_server(const char *serial, Uint16 max_size, Uint32 bit_rate) {
|
|
|
|
static SDL_bool enable_tunnel_forward(const char *serial, Uint16 local_port) {
|
|
|
|
|
|
|
|
process_t process = adb_forward(serial, local_port, SOCKET_NAME);
|
|
|
|
|
|
|
|
return process_check_success(process, "adb forward");
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static SDL_bool disable_tunnel_forward(const char *serial, Uint16 local_port) {
|
|
|
|
|
|
|
|
process_t process = adb_forward_remove(serial, local_port);
|
|
|
|
|
|
|
|
return process_check_success(process, "adb forward --remove");
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static SDL_bool enable_tunnel(struct server *server) {
|
|
|
|
|
|
|
|
if (enable_tunnel_reverse(server->serial, server->local_port)) {
|
|
|
|
|
|
|
|
return SDL_TRUE;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
LOGW("'adb reverse' failed, fallback to 'adb forward'");
|
|
|
|
|
|
|
|
server->tunnel_forward = SDL_TRUE;
|
|
|
|
|
|
|
|
return enable_tunnel_forward(server->serial, server->local_port);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static SDL_bool disable_tunnel(struct server *server) {
|
|
|
|
|
|
|
|
if (server->tunnel_forward) {
|
|
|
|
|
|
|
|
return disable_tunnel_forward(server->serial, server->local_port);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return disable_tunnel_reverse(server->serial);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static process_t execute_server(const char *serial,
|
|
|
|
|
|
|
|
Uint16 max_size, Uint32 bit_rate, SDL_bool tunnel_forward) {
|
|
|
|
char max_size_string[6];
|
|
|
|
char max_size_string[6];
|
|
|
|
char bit_rate_string[11];
|
|
|
|
char bit_rate_string[11];
|
|
|
|
sprintf(max_size_string, "%"PRIu16, max_size);
|
|
|
|
sprintf(max_size_string, "%"PRIu16, max_size);
|
|
|
|
@ -60,15 +89,48 @@ static process_t execute_server(const char *serial, Uint16 max_size, Uint32 bit_
|
|
|
|
"com.genymobile.scrcpy.Server",
|
|
|
|
"com.genymobile.scrcpy.Server",
|
|
|
|
max_size_string,
|
|
|
|
max_size_string,
|
|
|
|
bit_rate_string,
|
|
|
|
bit_rate_string,
|
|
|
|
|
|
|
|
tunnel_forward ? "true" : "false",
|
|
|
|
};
|
|
|
|
};
|
|
|
|
return adb_execute(serial, cmd, sizeof(cmd) / sizeof(cmd[0]));
|
|
|
|
return adb_execute(serial, cmd, sizeof(cmd) / sizeof(cmd[0]));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static socket_t listen_on_port(Uint16 port) {
|
|
|
|
|
|
|
|
#define IPV4_LOCALHOST 0x7F000001
|
|
|
|
#define IPV4_LOCALHOST 0x7F000001
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static socket_t listen_on_port(Uint16 port) {
|
|
|
|
return net_listen(IPV4_LOCALHOST, port, 1);
|
|
|
|
return net_listen(IPV4_LOCALHOST, port, 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static socket_t connect_and_read_byte(Uint16 port) {
|
|
|
|
|
|
|
|
socket_t socket = net_connect(IPV4_LOCALHOST, port);
|
|
|
|
|
|
|
|
if (socket == INVALID_SOCKET) {
|
|
|
|
|
|
|
|
return INVALID_SOCKET;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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
|
|
|
|
|
|
|
|
if (net_recv_all(socket, &byte, 1) != 1) {
|
|
|
|
|
|
|
|
// the server is not listening yet behind the adb tunnel
|
|
|
|
|
|
|
|
return INVALID_SOCKET;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return socket;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static socket_t connect_to_server(Uint16 port, Uint32 attempts, Uint32 delay) {
|
|
|
|
|
|
|
|
do {
|
|
|
|
|
|
|
|
LOGD("Remaining connection attempts: %d", (int) attempts);
|
|
|
|
|
|
|
|
socket_t socket = connect_and_read_byte(port);
|
|
|
|
|
|
|
|
if (socket != INVALID_SOCKET) {
|
|
|
|
|
|
|
|
// it worked!
|
|
|
|
|
|
|
|
return socket;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if (attempts) {
|
|
|
|
|
|
|
|
SDL_Delay(delay);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
} while (--attempts > 0);
|
|
|
|
|
|
|
|
return INVALID_SOCKET;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void close_socket(socket_t *socket) {
|
|
|
|
static void close_socket(socket_t *socket) {
|
|
|
|
SDL_assert(*socket != INVALID_SOCKET);
|
|
|
|
SDL_assert(*socket != INVALID_SOCKET);
|
|
|
|
net_shutdown(*socket, SHUT_RDWR);
|
|
|
|
net_shutdown(*socket, SHUT_RDWR);
|
|
|
|
@ -85,16 +147,25 @@ void server_init(struct server *server) {
|
|
|
|
|
|
|
|
|
|
|
|
SDL_bool server_start(struct server *server, const char *serial, Uint16 local_port,
|
|
|
|
SDL_bool server_start(struct server *server, const char *serial, Uint16 local_port,
|
|
|
|
Uint16 max_size, Uint32 bit_rate) {
|
|
|
|
Uint16 max_size, Uint32 bit_rate) {
|
|
|
|
|
|
|
|
server->local_port = local_port;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (serial) {
|
|
|
|
|
|
|
|
server->serial = SDL_strdup(serial);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (!push_server(serial)) {
|
|
|
|
if (!push_server(serial)) {
|
|
|
|
return SDL_FALSE;
|
|
|
|
return SDL_FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
server->server_copied_to_device = SDL_TRUE;
|
|
|
|
server->server_copied_to_device = SDL_TRUE;
|
|
|
|
|
|
|
|
|
|
|
|
if (!enable_tunnel(serial, local_port)) {
|
|
|
|
if (!enable_tunnel(server)) {
|
|
|
|
return SDL_FALSE;
|
|
|
|
return SDL_FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// if "adb reverse" does not work (e.g. over "adb connect"), it fallbacks to
|
|
|
|
|
|
|
|
// "adb forward", so the app socket is the client
|
|
|
|
|
|
|
|
if (!server->tunnel_forward) {
|
|
|
|
// At the application level, the device part is "the server" because it
|
|
|
|
// At the application level, the device part is "the server" because it
|
|
|
|
// serves video stream and control. However, at the network level, the
|
|
|
|
// serves video stream and control. However, at the network level, the
|
|
|
|
// client listens and the server connects to the client. That way, the
|
|
|
|
// client listens and the server connects to the client. That way, the
|
|
|
|
@ -104,44 +175,56 @@ SDL_bool server_start(struct server *server, const char *serial, Uint16 local_po
|
|
|
|
server->server_socket = listen_on_port(local_port);
|
|
|
|
server->server_socket = listen_on_port(local_port);
|
|
|
|
if (server->server_socket == INVALID_SOCKET) {
|
|
|
|
if (server->server_socket == INVALID_SOCKET) {
|
|
|
|
LOGE("Could not listen on port %" PRIu16, local_port);
|
|
|
|
LOGE("Could not listen on port %" PRIu16, local_port);
|
|
|
|
disable_tunnel(serial);
|
|
|
|
disable_tunnel(server);
|
|
|
|
return SDL_FALSE;
|
|
|
|
return SDL_FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// server will connect to our server socket
|
|
|
|
// server will connect to our server socket
|
|
|
|
server->process = execute_server(serial, max_size, bit_rate);
|
|
|
|
server->process = execute_server(serial, max_size, bit_rate, server->tunnel_forward);
|
|
|
|
if (server->process == PROCESS_NONE) {
|
|
|
|
if (server->process == PROCESS_NONE) {
|
|
|
|
|
|
|
|
if (!server->tunnel_forward) {
|
|
|
|
close_socket(&server->server_socket);
|
|
|
|
close_socket(&server->server_socket);
|
|
|
|
disable_tunnel(serial);
|
|
|
|
}
|
|
|
|
|
|
|
|
disable_tunnel(server);
|
|
|
|
return SDL_FALSE;
|
|
|
|
return SDL_FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
server->adb_reverse_enabled = SDL_TRUE;
|
|
|
|
server->tunnel_enabled = SDL_TRUE;
|
|
|
|
|
|
|
|
|
|
|
|
return SDL_TRUE;
|
|
|
|
return SDL_TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
socket_t server_connect_to(struct server *server, const char *serial, Uint32 timeout_ms) {
|
|
|
|
socket_t server_connect_to(struct server *server, Uint32 timeout_ms) {
|
|
|
|
|
|
|
|
if (!server->tunnel_forward) {
|
|
|
|
server->device_socket = net_accept(server->server_socket);
|
|
|
|
server->device_socket = net_accept(server->server_socket);
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
Uint32 attempts = 10;
|
|
|
|
|
|
|
|
Uint32 delay = 100; // ms
|
|
|
|
|
|
|
|
server->device_socket = connect_to_server(server->local_port, attempts, delay);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (server->device_socket == INVALID_SOCKET) {
|
|
|
|
if (server->device_socket == INVALID_SOCKET) {
|
|
|
|
return INVALID_SOCKET;
|
|
|
|
return INVALID_SOCKET;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!server->tunnel_forward) {
|
|
|
|
// we don't need the server socket anymore
|
|
|
|
// we don't need the server socket anymore
|
|
|
|
close_socket(&server->server_socket);
|
|
|
|
close_socket(&server->server_socket);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// the server is started, we can clean up the jar from the temporary folder
|
|
|
|
// the server is started, we can clean up the jar from the temporary folder
|
|
|
|
remove_server(serial); // ignore failure
|
|
|
|
remove_server(server->serial); // ignore failure
|
|
|
|
server->server_copied_to_device = SDL_FALSE;
|
|
|
|
server->server_copied_to_device = SDL_FALSE;
|
|
|
|
|
|
|
|
|
|
|
|
// we don't need the adb tunnel anymore
|
|
|
|
// we don't need the adb tunnel anymore
|
|
|
|
disable_tunnel(serial); // ignore failure
|
|
|
|
disable_tunnel(server); // ignore failure
|
|
|
|
server->adb_reverse_enabled = SDL_FALSE;
|
|
|
|
server->tunnel_enabled = SDL_FALSE;
|
|
|
|
|
|
|
|
|
|
|
|
return server->device_socket;
|
|
|
|
return server->device_socket;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void server_stop(struct server *server, const char *serial) {
|
|
|
|
void server_stop(struct server *server) {
|
|
|
|
SDL_assert(server->process != PROCESS_NONE);
|
|
|
|
SDL_assert(server->process != PROCESS_NONE);
|
|
|
|
|
|
|
|
|
|
|
|
if (!cmd_terminate(server->process)) {
|
|
|
|
if (!cmd_terminate(server->process)) {
|
|
|
|
@ -151,13 +234,13 @@ void server_stop(struct server *server, const char *serial) {
|
|
|
|
cmd_simple_wait(server->process, NULL); // ignore exit code
|
|
|
|
cmd_simple_wait(server->process, NULL); // ignore exit code
|
|
|
|
LOGD("Server terminated");
|
|
|
|
LOGD("Server terminated");
|
|
|
|
|
|
|
|
|
|
|
|
if (server->adb_reverse_enabled) {
|
|
|
|
if (server->tunnel_enabled) {
|
|
|
|
// ignore failure
|
|
|
|
// ignore failure
|
|
|
|
disable_tunnel(serial);
|
|
|
|
disable_tunnel(server);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (server->server_copied_to_device) {
|
|
|
|
if (server->server_copied_to_device) {
|
|
|
|
remove_server(serial); // ignore failure
|
|
|
|
remove_server(server->serial); // ignore failure
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@ -168,4 +251,5 @@ void server_destroy(struct server *server) {
|
|
|
|
if (server->device_socket != INVALID_SOCKET) {
|
|
|
|
if (server->device_socket != INVALID_SOCKET) {
|
|
|
|
close_socket(&server->device_socket);
|
|
|
|
close_socket(&server->device_socket);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
SDL_free((void *) server->serial);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|